【问题标题】:dynamical initialization of std::vector<unique_ptr<class T>>std::vector<unique_ptr<class T>> 的动态初始化
【发布时间】:2015-04-30 23:46:08
【问题描述】:

我有一个类 Grid 声明如下:

网格.h

#ifndef DATATEST_GRID_H
#define DATATEST_GRID_H

#include <memory>
#include <vector>
#include "Position.h"

class Grid
{
public:
    Grid(int length_x, int length_y);
    ~Grid();

    Position *at(int x, int y);
    void printGrid();

private:
    int length_x, length_y;
    std::vector<std::unique_ptr<Position>> grid;
};

#endif

它最重要的成员变量是vector&lt;unique_ptr&lt;Position&gt;&gt;,我用它来模拟一个二维数组,它的大小在运行时确定。 Position 的类声明如下:

位置.h

#ifndef DATATEST_POSITION_H
#define DATATEST_POSITION_H

#include <memory>
#include <string>

class Position {
public:
    Position(int x, int y);
    ~Position();

    std::string toString();
    int getX() { return x; };
    int getY() { return y; };

private:
    int x, y;
};

#endif

在网格的构造函数中,我想创建所需数量的位置并将它们添加到vector&lt;unique_ptr&lt;Position&gt;&gt;

Grid.cpp

#include "Grid.h"
#include <iostream>
#include <memory>
#include <vector>
#include "Position.h"

Grid::Grid(int length_x, int length_y) 
    : length_x(length_x), length_y(length_y)
{
    grid.resize(length_x * length_y);   

    for (int x = 0; x < length_x; x++) {
        for (int y = 0; y < length_y; y++) {
            /* Option 1 */
            std::unique_ptr<Position> temp = std::make_unique<Position>(x, y);
            grid.push_back(std::move(temp));

            /* Option 2 */
            // std::unique_ptr<Position> temp = std::make_unique<Position>(x, y);
            // grid.emplace_back(std::move(temp));

            /* Option 3 */
            // grid.push_back(std::make_unique<Position>(x, y)); 

            /* Option 4 */
            // grid.emplace_back(std::make_unique<Position>(x, y));
        }
    }
}

Grid::~Grid()
{
    grid.clear();
}

Position *Grid::at(int x, int y)
{
    if (x < 0 || x >= length_x || y < 0 || y >= length_y) {
        return nullptr;
    }
    else {
        return grid.at(x * (length_y) + y).get();
    }
}

void Grid::printGrid()
{
    for (int i = 0; i < grid.size(); i++) {
        std::cout << grid.at(i)->toString() << std::endl;
    }
}  

我正在通过为每个unique_ptr&lt;Position&gt; 调用 Position::toString 并将结果打印到控制台来测试访问。

位置.cpp

#include "Position.h"
#include <string>

Position::Position(int x, int y) 
    : x(x), y(y)
{
}

Position::~Position()
{
}

std::string Position::toString()
{
    return "Position(" + std::to_string(x) + ", " + std::to_string(y) + ")";
}

最后,主要功能:

Main.cpp

#include "Grid.h"
#include "Position.h"

int main()
{
    Grid g(2, 2);
    g.printGrid();

    return 0;
}

无论我以哪种方式填充vector&lt;unique_ptr&lt;Position&gt;&gt;,我总是收到以下错误:

CombatSim.exe 中 0x0087D8A3 处的第一次机会异常:0xC0000005:访问冲突读取位置 0x00000000。 CombatSim.exe 中 0x0087D8A3 处未处理的异常:0xC0000005:访问冲突读取位置 0x00000000。

据我所知,我可能会遇到以下四个问题之一:
1) 我错误地将 unique_ptr 添加到创建的 Position 对象到向量中
2) 我使用了错误的方法来动态创建 Position 对象。
3) 以上所有。
4) 我不知道的事情。

【问题讨论】:

  • 您将不得不向我们展示一个我们可以编译的程序并运行以重现问题。你的MCVE 会很好。你今天调试的那个。

标签: c++11 vector unique-ptr


【解决方案1】:

如果您之后要使用push_back 那些n 元素,请使用std::vector::reserve(n) 而不是std::vector::resize(n)

resize 将用初始化的对象填充向量,因此vector.size() 之后将是n

reserve 只会为所有 n 元素保留足够的空间,但不会插入任何对象。

【讨论】:

  • 谢谢!事实证明,这解决了我在另一篇文章中描述的问题。
【解决方案2】:

似乎调整网格大小将首先插入length_x * length_y 唯一指针,这些指针都指向0。您的 push_back 应该没问题,但您的真实元素从向量中的位置 length_x * length_y 开始。我认为删除线

grid.resize(length_x * length_y);

应该可以解决问题。也许其他人可以解释为什么会发生这种情况。

【讨论】:

  • 谢谢!根据cplusplus.com,当调用 resize 时,“如果 n 大于当前容器大小,则通过在末尾插入所需数量的元素来扩展内容,以达到 n 的大小。如果指定了 val,则新的元素被初始化为 val 的副本,否则,它们被值初始化。"
  • @user0815 建议先为所有length_x * length_y 元素保留空间,然后再将它们添加到向量中,以避免重复重新分配内存。
  • 是的,正确的。正如所指出的,我误认为resizereserve。因此行为是显而易见的。无论如何,我希望它有所帮助。
猜你喜欢
  • 1970-01-01
  • 2020-04-17
  • 2017-04-04
  • 2018-02-02
  • 2019-11-07
  • 2015-10-11
  • 2015-08-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多