如何调整一个 vector of vector of unique_ptr 的大小?

5

如何在一行内正确地调整一个unique_ptr向量的大小,而不会让gcc报告关于已删除函数的编译错误?

vector<vector<unique_ptr<A> >> a;
a.resize(..... )

更新: 这是我使用的代码,可以正常工作。

  int width, height;
  vector<vector<unique_ptr<A> >> a;
  a.resize(width);
  for (int i = 0; i < width; i++) {
      for (int j = 0; j < height; j++) {
          a.at(i).emplace_back(new A());

如果可能的话,我希望可以一次性调整大小,就像调整向量的大小一样。
vector<vector<int>> intObj;
intObj.resize(width, vector<int>(height, int()));

但是,每当我尝试使用以下方法调整上述向量的大小时,就会出现以下错误;

a.resize(x, vector<unique_ptr<A>>(y, unique_ptr<A>()));

error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = A; _Dp = std::default_delete<A>]’

感谢您的选择。

2
在这种情况下,vector<vector<...>> 对我来说是代码异味。你应该使用一个大小为 width*height 的单一向量,而不是向量的向量。注意:如果进行此更改,则可以调用 a.resize(width*height) - Simple
2
你尝试了哪些代码?出现了什么错误? - T.C.
2
@Simple 我不太同意。vector<vector<>> 更具可扩展性,因为用于保存数据的内存不需要连续,这对于大量数据可能是必要的。此外,我见过太多错误计算偏移量的情况... - Simon Kraemer
1
@Simple 单参数版本可能会起作用。 - T.C.
2
顺便说一句,emplace_back(new A())会造成内存泄漏。不要这样做;使用push_back(make_unique<A>()) - T.C.
显示剩余3条评论
2个回答

5
问题在于vector<unique_ptr<A>>是不可复制的类型,因为unique_ptr<A>不能被复制。 a.resize(x,vector<unique_ptr<A>>(y))使用了vector<unique_ptr<A>>的拷贝构造函数,a.resize(x,vector<unique_ptr<A>>(y,unique_ptr<A>()))则更糟糕,因为它使用了unique_ptr<A>vector<unique_ptr<A>>的拷贝构造函数。
两个解决方案:
  1. 使用一个大小为x*y的单一vector<unique_ptr<A>>。这意味着a.resize(x*y)将按预期工作。
  2. 或者,您需要遍历所有子向量。
循环示例:
a.resize(x);
for (auto& i : a) {
    i.resize(y);
}

编辑:如果您想要unique_ptr<A>指向默认构造的A而不是nullptr,则可以使用以下代码:

a.resize(x);
for (auto& i : a) {
    i.reserve(y);
    for (int j = 0; y != j; ++j) {
        i.push_back(std::make_unique<A>());
    }
}

如果您保持当前的设计,无法使用单个resize调用来完成所需操作。
编辑2:如果选择解决方案1,则可使用以下一个默认构造As的代码行。
std::generate_n(std::back_inserter(a), x*y, []{ return std::make_unique<A>(); });

这样做是否仍会导致所有的 unique_ptr 都被初始化为 nullptr - Simon Kraemer
1
@SimonKraemer,他原始代码中的 a.resize(x, vector<unique_ptr<A>>(y, unique_ptr<A>())) 是想要做什么。我明白他真正想要的是默认构造的 A,所以我稍作修改。 - Simple
@简单感谢。我想我必须选择第二种解决方案,否则代码的其他部分也必须进行更改。所以我猜没有办法调整大小不可复制类型的向量向量,因为调整大小会调用复制构造函数,除非我定义一个新的重载来使用移动? - user2924261
@user2924261,我不知道你使用move的重载会做什么,但请注意我的解决方案创建了unique_ptr,然后将它们移入向量中。另一种选择是使用某种value_ptr替代unique_ptr(阅读相关资料),当复制时执行深拷贝。 - Simple
非常感谢提供的信息,让我知道这个操作需要一个vector<unique_ptr<A>> (move)构造函数(除了类的移动构造函数/移动=操作符)。在我看来,这解释了很多问题。同时也要点赞那个一行代码的解决方案(我忘记了back_inserter...) - gilgamash

-4

std::unique_ptr 不可复制,使用 std::shared_ptr 可以获得完整的容器支持。


...并创建一个w*h指针的容器,全部指向同一个对象? - T.C.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接