【问题标题】:unique_ptr as class member and move semantics fail to compile with clangunique_ptr 作为类成员和移动语义无法使用 clang 编译
【发布时间】:2013-07-18 14:25:55
【问题描述】:

我无法让 clang(Apple LLVM 版本 4.2 (clang-425.0.28))编译这些类:

struct A {
    int f(){return 2;}
};
class Cl{
     std::unique_ptr<A> ptr;

public:
     Cl(){ptr = std::unique_ptr<A>(new A);}

     Cl(const Cl& x) : ptr(new A(*x.ptr)) { }
     Cl(Cl&& x) : ptr(std::move(x.ptr)) { }
     Cl(std::unique_ptr<A> p) : ptr(std::move(p))  { }

    void m_ptr(std::unique_ptr<A> p){
        ptr = std::unique_ptr<A>(std::move(p));
    }
    double run(){return ptr->f();}
};

我想按如下方式运行构造函数:

std::unique_ptr<A> ptrB (new A);
Cl C = Cl(ptrB);

但如果我这样做,我会收到以下编译器错误: ../src/C++11-2.cpp:66:10:错误:调用“std::unique_ptr”的隐式删除的复制构造函数 C.m_ptr(ptrB);

我可以通过运行 Cl(std::move(ptrB)) 来解决编译器问题,但这实际上并没有将 A 的所有权从 ptrB 移开:我仍然可以运行 ptrB-&gt;f() 而不会导致运行时崩溃......其次,构造函数不是很满意,因为我想在类接口中隐藏std::move的实现。

提前致谢。

【问题讨论】:

    标签: compiler-errors unique-ptr llvm-clang


    【解决方案1】:

    由于 ptrB 按值 传递给 Cl 的复制构造函数,因此对 Cl(ptrB) 的调用会尝试创建 ptrB 的副本,而后者又会调用 unique_ptr 的(显然已禁用)复制构造函数。为了避免创建 ptrB 的额外副本,请执行以下操作:

    Cl C = Cl(std::unique_ptr<A>(new A)); //A temporary is created on initialization, no extra copy steps performed
    

    或者:

    std::unique_ptr<A> ptrB (new A);
    Cl C = Cl(std::move(ptrB)); //Move semantics used. Again, no extra copy steps
    

    或者,在复制构造函数中使用引用传递(右值或左值):

    class Cl{
    
    //...
    public:
    //...
         Cl(std::unique_ptr<A> &p) : ptr(std::move(p))  { }
    
    //...
    
    };
    
    std::unique_ptr<A> ptrB (new A);
    Cl C = Cl(ptrB);
    

    P.S 哦,顺便说一句:对象在 std::move() 之后保持未指定,但 有效 状态。我相信这意味着您仍然可以调用 ptrB->f(),并且可以保证 返回 2 :)

    【讨论】:

    • 谢谢!引用传递最适合我,因为我希望将类 Cl 的实现保留在接口之外。在我将答案标记为正确之前,只需一个简单的问题:通过引用构造函数传递,是否有任何复制步骤或正在创建的临时对象? (我知道你使用移动语义,但这对我来说是新的,所以我还在问愚蠢的问题:))
    • 不。这是一个经典的参考传递
    猜你喜欢
    • 2021-06-08
    • 1970-01-01
    • 2013-04-07
    • 2011-07-08
    • 2015-10-24
    • 1970-01-01
    • 1970-01-01
    • 2018-04-30
    • 1970-01-01
    相关资源
    最近更新 更多