当我使用初始化列表格式实例化窗口小部件数组时,指向成员变量窗口小部件实例的裸指针编译但在更改为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<> }
错误:
$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]
我对这两种情况都感到茫然:幕后产生删除fcxn的机制;或者更简单地说,为什么std :: unique_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; };
现在程序编译并运行.我很欣赏标准人员出于某种原因编写了规范,因此我将我的结果作为一个善意的专业化发布在我的案例中,我真的想强调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; };
请注意,根本没有~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] // .. }
我想,新的c 11风格迭代正在进行对象复制,这是不言而喻的.
解决方法
When an aggregate is initialized by an initializer list,as specified in 8.5.4,the elements of the initializer listare taken as initializers for the members of the aggregate,in increasing subscript or member order. Each member is copy-initialized from the corresponding initializer-clause. […]
然后,对于每个元素,复制初始化涉及创建目标类型的临时值,然后使用该临时值来复制构造数组的元素.
但是,您的类包含一个类型为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 }