std::vector 个矢量取消分配其 shared_ptr 内容(堆栈实体对象的使用不正确?)

std::vector of vectors deallocates its shared_ptr content (incorrect usage of stack solid objects?)

shared_ptr 的向量的向量释放其 Piece 实例。 我在我的 Board class 中创建它是这样的:

std::vector < std::vector < std::shared_ptr <Piece> > > board; 

但是每次内部循环离开范围时它都会释放:

Board::board with capacity 10 size: 10
Piece born 0x7faedbc1dc78
Row 0 Column 0 piece0x7faedbc1dc78
Piece born 0x7faede303fd8
Row 1 Column 0 piece0x7faede303fd8
Piece born 0x7faede30d2a8
Row 2 Column 0 piece0x7faede30d2a8
Piece born 0x7faede30d248
Row 3 Column 0 piece0x7faede30d248
Piece born 0x7faede30d348
Row 4 Column 0 piece0x7faede30d348
Piece born 0x7faede30d368
Row 5 Column 0 piece0x7faede30d368
Piece born 0x7faede30d4c8
Row 6 Column 0 piece0x7faede30d4c8
Piece born 0x7faede30d4e8
Row 7 Column 0 piece0x7faede30d4e8
Piece born 0x7faede30d508
Row 8 Column 0 piece0x7faede30d508
Piece born 0x7faede30d528
Row 9 Column 0 piece0x7faede30d528
Piece death 0x7faede30d528
Piece death 0x7faede30d508
Piece death 0x7faede30d4e8
Piece death 0x7faede30d4c8
Piece death 0x7faede30d368
Piece death 0x7faede30d348
Piece death 0x7faede30d248
Piece death 0x7faede30d2a8
Piece death 0x7faede303fd8
Piece death 0x7faedbc1dc78
Piece born 0x7faede303fd8
Row 0 Column 1 piece0x7faede303fd8
Piece born 0x7faede30d2a8
Row 1 Column 1 piece0x7faede30d2a8
Piece born 0x7faede30d248
Row 2 Column 1 piece0x7faede30d248
Piece born 0x7faedbe7db98
Row 3 Column 1 piece0x7faedbe7db98
Piece born 0x7faedbe8f6a8
Row 4 Column 1 piece0x7faedbe8f6a8
Piece born 0x7faedbe8f868
Row 5 Column 1 piece0x7faedbe8f868
Piece born 0x7faedbe8f888
Row 6 Column 1 piece0x7faedbe8f888
Piece born 0x7faedbe8f8a8
Row 7 Column 1 piece0x7faedbe8f8a8
Piece born 0x7faedbe8f8c8
Row 8 Column 1 piece0x7faedbe8f8c8
Piece born 0x7faedbe8f8e8
Row 9 Column 1 piece0x7faedbe8f8e8
Piece death 0x7faedbe8f8e8
Piece death 0x7faedbe8f8c8
Piece death 0x7faedbe8f8a8
Piece death 0x7faedbe8f888
Piece death 0x7faedbe8f868
Piece death 0x7faedbe8f6a8
Piece death 0x7faedbe7db98
Piece death 0x7faede30d248
Piece death 0x7faede30d2a8
Piece death 0x7faede303fd8
Piece born 0x7faedbe7db98
Row 0 Column 2 piece0x7faedbe7db98 ...

这是董事会 class 代码:

#include "Board.h"
#include <iostream>

using namespace std;

Board::Board(int width_, int height_) : width(width_), height(height_), board(height)
{
    cout << "Board::board with capacity " << board.capacity() << " size: " << board.size() << endl;
//    board = vector< vector < shared_ptr < Piece >>> (height) ;

    for (int i=0; i<height; i++)
    {
        vector < shared_ptr < Piece > > row(width);
        board[i] = row;

        for (int j=0;j<width;j++) {
            shared_ptr< Piece > piece = make_shared<Piece>();
            row[j] = piece;
            cout << "Row " << j << " Column " << i << " piece" << &*piece << endl;
        }
    }
}

相关Piece代码(基本上就是乱码)

class Piece {
public:
    Piece() { std::cout << "Piece born " << this << std::endl;}
    ~Piece() { std::cout << "Piece death " << this << std::endl;}
    Piece(const Piece &rhs) {
        std::cout << "Piece copy " << this << " from " << &rhs << std::endl;
    }
    Piece & operator=(const Piece & rhs) {
        std::cout << "Piece assigned " << this << " from " << &rhs << std::endl;
        return *this;
    }
};

没有调用复制或赋值运算符。所以我相信这不是由于向量的自我重新分配,因为我在 Board 的构造函数中预先分配了最外层的向量(以及在内部循环中分配给 "width" 的局部向量)

board[i] = row;

这会将 row 向量 在赋值时 的内容复制到 board[i] 中。然后,您继续填充局部 row 向量,但不做任何其他操作。

将赋值移动到循环之后:

for (int i=0; i<height; i++)
{
    vector < shared_ptr < Piece > > row(width);

    for (int j=0;j<width;j++) {
        shared_ptr< Piece > piece = make_shared<Piece>();
        row[j] = piece;
        cout << "Row " << j << " Column " << i << " piece" << &*piece << endl;
    }
    board[i] = std::move(row);
}

或者,要完全摆脱赋值,您可以引入 row 作为简单的别名:

for (int i=0; i<height; i++)
{
    auto &row = board[i];
    row.resize(width);

    for (int j=0;j<width;j++) {
        shared_ptr< Piece > piece = make_shared<Piece>();
        row[j] = piece;
        cout << "Row " << j << " Column " << i << " piece" << &*piece << endl;
    }
}

如果你想更精简代码,可以这样做(我什至会说这样更清晰):

for (int i=0; i<height; i++)
{
    auto &row = board[i];

    for (int j=0;j<width;j++) {
        row.emplace_back(make_shared<Piece>());
        cout << "Row " << j << " Column " << i << " piece" << row.back().get() << endl;
    }
}

请注意 std::shared_ptr::get() returns 原始指针,我个人认为它优于 &*