初始变量没有复制构造函数
我有一些类(窗口)没有复制构造函数(它是私有的)。我不明白如何初始化此类的VAR在我自己的类:初始变量没有复制构造函数
class MyClass
{
Window obj; // Hasn't copy constructor
public:
void init()
{
obj = Window(/* constructor params */); // [error]
obj(/* constructor params */); // [error]
}
}
错误1:initializing argument 1 of ‘Window::Window(WindowHandle, const sf::WindowSettings&)’
错误2:‘NonCopyable& NonCopyable::operator=(const NonCopyable&)’ is private
但它以这种方式工作:
Window obj(/* constructor params */);
您的MyClass
需要一个构造函数来初始化obj
成员。
class MyClass
{
private:
Window obj;
public:
MyClass() : obj(/* constructor params */) // This is an initializer list
{}
};
如果您需要init()
功能,并且Window
对象提供某种自己的 init()
功能,你可以这样做:
class MyClass
{
private:
Window obj;
public:
void init()
{
obj.init(/* init params */); // Window's own init() function
}
};
如果Window
类没有像什么init()
功能,你可以使用堆(不建议,除非你绝对必须):
class MyClass
{
private:
// Alternatively, we can use a smart pointer here and avoid
// managing memory ourselves.
Window* obj;
public:
MyClass() : obj(0) {}
~MyClass() { uninit(); }
void init()
{
uninit();
obj = new Window(/* constructor params */);
}
void uninit()
{
if(obj != 0)
{
delete obj;
obj = 0;
}
}
};
如果Window
类声明私有拷贝构造函数和/或拷贝赋值运算符,则不能将新的Window
实例指定为obj
。
删除一个空指针是[安全](http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.8),所以你不需要'if(obj! = 0)'检查uninit函数。 – 2010-05-29 13:48:11
当且仅当它是默认的全局删除并且全局删除不是越野时,调用NULL指针上的删除是安全的。我编写的可移植代码在不同的构建和执行环境下需要健壮,因此我总是在删除之前检查NULL。 – 2010-05-29 14:26:43
该标准明确规定,当用空指针调用时,delete应该表现正确。如果他们不符合这样一个简单的要求,我会非常害怕我会遇到的其他惊喜,所以我会偏离envs。 – 2010-05-29 16:58:06
class MyClass
{
Window obj; // Hasn't copy constructor
public:
MyClass() :
obj(/* constructor params */)
{
}
}
这也适用于参考。您可以在初始化程序列表中分配任何成员变量。但它只能在构造函数中使用。
如果你想让它构造以外的地方工作,你需要使用一个指针:
class MyClass
{
Window *obj;
public:
void init()
{
obj = new Window(/* constructor params */);
}
}
一定要在你的拆解利用delete
要解除obj
(并进行解构虚拟如有必要)。
只有构造函数可以有初始化列表。 – 2010-05-29 13:14:48
@In silico,True;我忽略了这一点。抱歉。 – strager 2010-05-29 13:15:46
如果您要使用堆,请确保'obj'管理得当。看到我的答案是如何做到这一点。 – 2010-05-29 13:23:24
整点不会让你克隆它。
初始化这样的:Window OBJ
或
窗口& OBJ = somefunctionConstructingSuchAWindow(其他的构造,而不是复制一个的参数)();
如果您的拷贝构造函数是私有的,那么类确实有有拷贝构造函数。看起来你的班级同时拥有私人的ctor和赋值op,这就解释了第二个错误信息。第一个错误信息与您没有显示的WindowHandle类有关。
为了更好地理解这个,我们需要看到Window类 - 例如它是否有默认的构造函数?
http://www.sfml-dev.org/documentation/1.6/classsf_1_1Window.htm#49db47a79ca98b7d65087adeea06e919 – Ockonal 2010-05-29 13:27:04
@Neil:'Window'不需要默认构造。我们需要的唯一要求是其析构函数不会抛出(这当然只有良好的意义)。之后有内存对齐问题等......但是,我们有这样的库;) – 2010-05-29 17:33:40
如果Window
没有复制构造函数,则不能为其分配Window
类的其他对象。您只能使用初始化程序列表从MyClass
的构造函数初始化obj
。例如:
class MyClass
{
Window obj; // Hasn't copy constructor
public:
MyClass()
: obj(/*constructor params*/)
{
/*...*/
}
}
类成员的初始化应该在类的构造函数来完成像下面的例子:
class MyClass
{
public:
MyClass(/* constructor params */);
private:
Window m_obj; // Hasn't copy constructor
};
MyClass::MyClass(/* constructor params */) : m_obj(/* constructor params */)
{
}
我想我会得到彻底的是丢弃(读,直到临睡前所有烟)结束,但......假设窗的构造函数不会抛出:
void MyClass::init()
{
obj::~Window(); // destroy the object
new (&obj) Window(...); // construct the object
};
我当然强调不扔对构造函数的要求就好像它抛出一样,你会留下一个非常泥泞的情况:MyClass
的析构函数将调用Window
的析构函数,无论该对象是否因存在构造失败而处于活动状态并被踢或抛弃,以及在后一种情况下,你会得到未定义的行为。
当然,一个典型的事情将因此成为std::unique_ptr<Window>
但我们有动态分配的障碍,其中明确的情况不会这样做吗?
所以你会更好使用库:Boost.Optional。
class MyClass
{
public:
private:
boost::optional<Window> obj;
};
语法调用类似于指针:
obj->foo();
但一个好处是,你得到就地销毁/建筑与更安全的语义。销毁很容易:
// both call ~Window() if an instance had been constructed
obj.reset();
obj = detail::none_t();
对于建筑使用一个TypedInPlaceFactory。而对于分配太...这当然清除了以前的实例(如果有的话)第一:
void MyClass::init(Arg1 arg1, Arg2 arg2)
{
obj = boost::in_place<Window>(arg1, arg2);
}
的主要优点是,如果施工过程中遇到的现任何异常,optional
对象仍留在unitialized
状态,这是完全可行的,因此您不必担心未定义的行为。
所以基本上就像有不同之处在于神奇的是,对象没有动态分配,从而保证同样的表演智能指针拥有一个动态分配的对象......“正常的”对象:)
我应该补充说,不可复制的障碍是InPlaceFactory创建背后的原因之一。
是否有你的类使用'init()'成员函数而不是使用__constructor__的原因? – sbi 2010-05-29 13:21:48
@sbi,是的,有。不要asky为什么=) – Ockonal 2010-05-29 13:24:59
我重新说:你有使用'init()'成员的__good__原因吗? (一个很好的理由是,例如,如果初始化需要调用虚函数,那么需要两步构造。) – sbi 2010-05-29 22:34:32