如果结构具有不可复制的成员,如何初始化该结构?

时间:2019-01-21 15:04:54

标签: c++ inheritance

我想创建一个结构,该结构具有一些原始成员和一个unique_ptr,该结构无法复制。我试图通过禁用复制并添加默认的move构造函数来解决此问题,但是它不起作用。编译器尝试查找2参数构造函数,但没有任何参数:

 In function 'int main()':
37:3: error: no matching function for call to 'ListElem::ListElem(<brace-enclosed initializer list>)'
37:3: note: candidates are:
25:2: note: ListElem::ListElem(ListElem&&)
25:2: note:   candidate expects 1 argument, 2 provided
20:5: note: constexpr ListElem::ListElem()
20:5: note:   candidate expects 0 arguments, 2 provided

代码是:

// Example program
#include <iostream>
#include <memory>
#include <vector>

class MyObj {
    public:
        virtual ~MyObj(){}
};

class MyObj2 : public MyObj{
    public:
        virtual ~MyObj2(){}
};

struct ListElem {
    std::unique_ptr<MyObj> item;
    int some_counter = 0;

    ListElem() = default;

    ListElem(ListElem const& e) = delete;
    ListElem& operator=(ListElem const& e) = delete;

    ListElem(ListElem&& e) = default;
    ListElem& operator=(ListElem&& e) = default;

};

int main()
{
  std::vector<ListElem> elems;

  ListElem item{
      std::unique_ptr<MyObj>(new MyObj2()),
      10
  };
  elems.push_back(std::move(item));
}

如何解决此错误?


修改

我将构造函数更改为此:

ListElem(std::unique_ptr<MyObj>&& _item, int _some_counter): item(_item), some_counter(_some_counter) {}

但是现在我得到error: use of deleted function

3 个答案:

答案 0 :(得分:2)

您可以从类(1)中删除所有构造函数声明。然后,该类将是一个聚合,并且可以通过聚合初始化(您要尝试执行的操作)进行初始化。请注意,无需手动删除复制构造函数或默认将move构造函数删除,两者都会自动发生。

[Live example]

当然,替代方法是提供一个两参数构造函数,以接收要传递的参数。请注意,即使在这种情况下,也不需要手动删除和默认复制/移动操作。


(1)请记住,structclass都引入了类类型。它们之间的唯一区别是对基和成员的隐式访问控制(分别为publicprivate);它们在其他方面是相同的。

答案 1 :(得分:1)

在没有构造函数的情况下直接初始化结构称为聚合初始化。这仅在某些情况下有效。例如。该类不应具有任何构造函数(默认值是可以的)。似乎在c ++ 14中解除了一些限制,因此如其他答案所述,它在c ++ 14或更高版本中工作正常。但不是在c ++ 11中。 https://gcc.godbolt.org/z/ZTFUz3

  ListElem item{
      std::unique_ptr<MyObj>(new MyObj2()),
      10
  };

在进行编辑时,失败的原因是您错过了移动unique_ptr的过程。添加std::move,它在两个版本中均应正常工作。

https://gcc.godbolt.org/z/uFmZvC

ListElem(std::unique_ptr<MyObj>&& _item, int _some_counter)
: item(std::move(_item)), 
some_counter(_some_counter) 
{}

答案 2 :(得分:0)

问题是成员 some_counter 的初始化:这不允许对该结构进行聚合初始化,请在此处https://en.cppreference.com/w/cpp/language/aggregate_initialization中进行检查,这说明该类(结构)不应没有默认的成员初始化器(从C ++ 11到C ++ 14)。

此处代码已更改:

// Example program
#include <iostream>
#include <memory>
#include <vector>

class MyObj {
    public:
        virtual ~MyObj(){}
};

class MyObj2 : public MyObj{
    public:
        virtual ~MyObj2(){}
};

struct ListElem {
    std::unique_ptr<MyObj> item;
    int some_counter;

    ListElem() = default;

    ListElem(ListElem const& e) = delete;
    ListElem& operator=(ListElem const& e) = delete;

    ListElem(ListElem&& e) = default;
    ListElem& operator=(ListElem&& e) = default;
};

int main()
{
  std::vector<ListElem> elems;

  ListElem item { std::unique_ptr<MyObj>(new MyObj2()), 10};

  elems.push_back(std::move(item));
}

链接到代码:https://wandbox.org/permlink/InZQwGKFyWKmCJrL