【问题标题】:std::make_unique and unique_ptrstd::make_unique 和 unique_ptr
【发布时间】:2021-08-27 08:37:46
【问题描述】:

如果我没看错的话,cppreference 表示以下两个结构对于 C++14 及更高版本中的非数组类型应该是等效的:

make_unique<T>(T());
unique_ptr<T>(new T());

我显然没有理解其中的微妙之处。这是一个示例(带有标题和脚手架的完整文件是here。在示例中,我希望cmp3cmp4 具有相同的效果,但cmp4 无法编译。

template <typename T>
class DbCell {
   public:
    DbCell() {}
    DbCell(const T& v) : value_(v.value_) {}
    DbCell(T&& v) : value_(move(v.value_)) {}
    ~DbCell() {}
   private:
    T value_;
};

struct ChapterStats {
    ChapterStats() {}
};
class ChapterMap {
   public:
    ChapterMap() {}
    ChapterMap(const ChapterMap&) = delete;
    ChapterMap(ChapterMap&& cm) : the_map_(move(cm.the_map_)) {}

   private:
    map<string, unique_ptr<ChapterStats>> the_map_;
};
void foo() {
    DbCell<ChapterMap> cm;

    unique_ptr<DbCell<int>> cmp1 =
        make_unique<DbCell<int>>(DbCell<int>());

    unique_ptr<ChapterMap> cmp2 = make_unique<ChapterMap>(ChapterMap());

    unique_ptr<DbCell<ChapterMap>> cmp3 =
        unique_ptr<DbCell<ChapterMap>>(new DbCell<ChapterMap>());

    // This next fails, even though I think it should be equivalent to cmp3.
    cout << "> cmp4:" << endl;
    unique_ptr<DbCell<ChapterMap>> cmp4 =
        make_unique<DbCell<ChapterMap>>(new DbCell<ChapterMap>());
}

没有cmp4,输出是这样的(添加适当的打印语句):

Constructed ChapterMap.
Constructed DbCell.
> cmp1:
Constructed DbCell.
> cmp2:
Constructed ChapterMap.
Moved ChapterMap.
> cmp3:
Constructed ChapterMap.
Constructed DbCell.

使用cmp4,编译器错误是这样的:

In file included from rgr.cc:6:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/memory:81:
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/unique_ptr.h:765:34: error: no matching constructor for initialization of 'DbCell<ChapterMap>'
    { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
                                 ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
rgr.cc:61:9: note: in instantiation of function template specialization 'std::make_unique<DbCell<ChapterMap>, DbCell<ChapterMap> *>' requested here
        make_unique<DbCell<ChapterMap>>(new DbCell<ChapterMap>());
        ^
rgr.cc:18:7: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'DbCell<ChapterMap> *' to 'const DbCell<ChapterMap>' for 1st argument; dereference the argument with *
class DbCell {
      ^
rgr.cc:21:5: note: candidate constructor not viable: no known conversion from 'DbCell<ChapterMap> *' to 'const ChapterMap' for 1st argument
    DbCell(const T& v) : value_(v.value_) {
    ^
rgr.cc:24:5: note: candidate constructor not viable: no known conversion from 'DbCell<ChapterMap> *' to 'ChapterMap' for 1st argument
    DbCell(T&& v) : value_(move(v.value_)) { cout << "Moved DbCell." << endl; }
    ^
rgr.cc:20:5: note: candidate constructor not viable: requires 0 arguments, but 1 was provided
    DbCell() { cout << "Constructed DbCell." << endl; }
    ^
1 error generated.

让我感到困惑的部分是编译器抱怨隐式删除的 DbCell&lt;ChapterMap&gt; 复制构造函数,但我已经定义了一个(我不想要,但仅用于示例)。

【问题讨论】:

  • make_unique 代表你调用T 的构造函数; make_unique 的参数被传递给 T 的构造函数。所以cmp4 需要一个复制或移动构造函数。
  • 您没有为DbCell&lt;T&gt; 创建复制/移动构造函数,因为您定义的ctor 采用T const &amp; 而不是DbCell&lt;T&gt; const &amp;
  • make_unique&lt;T&gt;(T()); 等价于unique_ptr&lt;T&gt;(new T(T()));
  • @AlanBirtles 你是对的。我正在寻找我的 MRE 中的错误(也就是说,我为什么专门写这个)。
  • 感谢@Thomas,DbCell 构造函数中模板参数的遗漏是问题的核心。 (也就是说,我非常感谢我有时不小心错误地调用了make_unique,并且编译器并不总是警告我。)

标签: c++ c++14 unique-ptr


【解决方案1】:

这两个相同:

   make_unique<T>(T());
   unique_ptr<T>(new T());

这两个是相同的:

   make_unique<T>();
   unique_ptr<T>(new T());

在第一个中,您在调用 make_unique&lt;T&gt; 时有一个额外的移动/复制 ctor。

【讨论】:

    【解决方案2】:

    对于cmp4,您应该使用

    unique_ptr<DbCell<ChapterMap>> cmp4 =
            make_unique<DbCell<ChapterMap>>(/*empty*/);
    

    std::make_unique 调用其类型的构造函数,在您的情况下,这将是一个构造函数,它带有指向 DbCell 的指针,而您没有。编译器错误消息突出显示了这一点:

    rgr.cc:18:7: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'DbCell<ChapterMap> *' to 'const DbCell<ChapterMap>' for 1st argument; dereference the argument with *
    

    【讨论】:

      猜你喜欢
      • 2014-04-29
      • 1970-01-01
      • 1970-01-01
      • 2019-05-27
      • 1970-01-01
      • 1970-01-01
      • 2022-01-20
      • 1970-01-01
      • 2017-05-15
      相关资源
      最近更新 更多