std :: unique_ptr删除了函数,initializer_list - 驱动分配

Jay*_*Nyc 6 c++ initializer-list unique-ptr c++11

所有,

当我使用初始化列表格式实例化窗口小部件数组时,指向成员变量窗口小部件实例的裸指针会编译,但在更改为std :: unique_ptr <> gcc后会出现有关已删除函数的编译错误.

$ uname -a

Linux .. 3.5.0-21-generic#32-Ubuntu SMP Tue Dec 11 18:51:59 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux

$ g ++ --version

g ++(Ubuntu/Linaro 4.7.2-5ubuntu1)4.7.2

此代码提供以下编译器错误:

#include <stdlib.h>
#include <memory>

class Widget
{
public:
    Widget() {}
};

class W1 : public Widget
{
public:
    W1() {}
};

class W2 : public Widget
{
public:
    W2() {}
};

class WFactory
{
public:
    WFactory(const int i)   : _w(new W1()) {}
    WFactory(const char* s) : _w(new W2()) {}

    ~WFactory() { _w.reset(nullptr); }
    // ~WFactory() { delete _w; }  <--- for naked ptr

private:
    // NOTE: does not compile
    std::unique_ptr<Widget>  _w; 
    // NOTE: does compile
    // Widget* _w;
};

int main()
{
    std::unique_ptr<Widget> a(new W1()); // <--- compiles fine

    WFactory wf[] { 4, "msg" };          // <--- compiler error using unique_ptr<>
}
Run Code Online (Sandbox Code Playgroud)

错误:

$ g++ -o unique_ptr  -std=c++11 -Wall  unique_ptr.cpp 
unique_ptr.cpp: In function ‘int main()’:
unique_ptr.cpp:36:30: error: use of deleted function ‘WFactory::WFactory(const WFactory&)’
unique_ptr.cpp:22:7: note: ‘WFactory::WFactory(const WFactory&)’ is implicitly deleted because the default definition would be ill-formed:
unique_ptr.cpp:22:7: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Widget; _Dp = std::default_delete<Widget>; std::unique_ptr<_Tp, _Dp> = std::unique_ptr<Widget>]’
In file included from /usr/include/c++/4.7/memory:86:0,
             from unique_ptr.cpp:2:
/usr/include/c++/4.7/bits/unique_ptr.h:262:7: error: declared here
unique_ptr.cpp:36:30: error: use of deleted function ‘WFactory::WFactory(const WFactory&)’
unique_ptr.cpp:36:14: warning: unused variable ‘wf’ [-Wunused-variable]
Run Code Online (Sandbox Code Playgroud)

我对这两种情况都感到茫然:幕后产生删除fcxn的机制; 或者更简单地说,为什么std :: unique_ptr <>的表现力与裸体ptr相比似乎受到限制.

我的问题是:

  • 飞行员错误?
  • 编译错误?
  • 我可以通过某些更改获得我想要的代码吗?

谢谢.

编辑1

根据您的回答,我很感激,我可以对WFactory进行以下更改:

(标记为不道德的代码)

class WFactory
{
public:
    WFactory(const WFactory& wf)
    {
        (const_cast<WFactory&>(wf)).moveto(_w);
    }

    WFactory(const int i)   : _w(new W1()) {}
    WFactory(const char* s) : _w(new W2()) {}

    ~WFactory() { _w.reset(nullptr); }

    void moveto(std::unique_ptr<Widget>& w)
    {
        w = std::move(_w);
    }
private:
    std::unique_ptr<Widget>  _w; 
};
Run Code Online (Sandbox Code Playgroud)

现在程序编译并运行.我很欣赏标准人员出于某种原因编写了规范,因此我将我的结果作为一个善意的专业化发布在我的案例中,我真的想强调ptr的独特性.

编辑2

基于Jonathan的回复,以下代码不会抑制隐式移动ctor:

class WFactory
{
public:
    WFactory(const int i)   : _w(new W1()) {}
    WFactory(const char* s) : _w(new W2()) {}

private:
    std::unique_ptr<Widget>  _w; 
};
Run Code Online (Sandbox Code Playgroud)

请注意,根本没有~WFactory() {..}.

也许有ya-ans,但是我发现在Main()中使用c ++ 11风格的迭代而不是wf []会带来no-copy-ctor-for-WFactory错误.那是:

int Main()
..
    WFactory wf[] { 4, "msg" };

    for ( WFactory iwf : wf )    <---- compiler error again
        // ..

    for (unsigned i = 0; i < 2; ++i)  <--- gcc happy
        wf[i] //  ..
}
Run Code Online (Sandbox Code Playgroud)

我想新的c ++ 11风格的迭代正在进行对象复制,这是不言而喻的.

And*_*owl 8

根据C++ 11标准的第8.5.1/2段:

当初始化程序列表初始化聚合时,如8.5.4中所述,初始化程序列表的元素将作为聚合成员的初始化程序,增加下标或成员顺序.每个成员都是从相应的initializer子句复制初始化的.[...]

然后,对于每个元素,复制初始化涉及创建目标类型的临时值,然后使用该临时值来复制构造数组的元素.

但是,您的类包含一个类型为实例的成员,该成员unique_ptr是不可复制的.这使得你的课程也不可复制.

此外,虽然unique_ptr可移动的,但是您的类不是,因为编译器隐式生成移动构造函数会因显式定义的析构函数的存在而被抑制.如果不是这种情况(即,如果您为类明确定义了移动构造函数),则复制初始化将起作用(参见8.5/15).

尝试更改以下定义WFactory以查看:

class WFactory
{
public:
    WFactory(const int i)   : _w(new W1()) {}
    WFactory(const char* s) : _w(new W2()) {}
    WFactory(WFactory&& f) : _w(std::move(f._w)) {}
    ~WFactory() { _w.reset(nullptr); }
private:
    std::unique_ptr<Widget> _w;
};

int main()
{
    std::unique_ptr<Widget> a(new W1());
    WFactory wf[] { 4, "msg" };          // OK
}
Run Code Online (Sandbox Code Playgroud)