请考虑以下代码:
class Foo {
public:
explicit Foo(double) {}
};
Foo * test();
Foo * test() {
return new Foo(Foo(1.0)); // (1)
}
我的问题与第(1)行有关。这非常类似于一个bug,我花了一些时间才找到它。我没有注意到由于复制/粘贴错误,该类型已经指定了两次。正确的行文显然是:
return new Foo(1.0);
有趣的是,这一更改似乎也没有编译警告:
return new Foo(Foo(Foo(Foo(1.0))));
为什么这些示例编译时不带警告,即使使用-Wall -Weverything
标志?为什么Foo::Foo(double)
接受Foo的一个实例作为一个有效的double
参数?这是运算符的一些特殊行为吗?
我的原始代码是在一个更大的上下文中,并且用两个基于LLVM-3的编译器进行了测试.都是在没有警告或错误情况下编译的。有了一种,代码实际上起了我预期的作用,事实上,有一段时间我没有意识到有一个bug。对于另一个实例,Foo实例的行为非常奇怪--我无法真正正确地描述它--就好像返回指针的稍后副本“神奇地”变成了与原始指针不同的值,从而导致两个协作对象之间的状态不匹配,这些对象应该持有指向共享Foo的等效指针,但由于某种原因,在分配后保持不同的值。在我明白这是怎么回事之前,这看起来真的很奇怪!
有趣的是,下面这两个编译器一起编译:
class Foo { public: explicit Foo(double) {} };
class Bar { public: explicit Bar(double) {} };
Foo * testFoo() { return new Foo(Foo(1.0)); }
Bar * testBar() { return new Bar(Bar(1.0)); }
但以下版本没有:
Foo * testFooBar() { return new Foo(Bar(1.0)); }
发布于 2014-08-02 02:55:05
编译器会自动生成一个复制构造函数Foo(const Foo&)
,可能还会根据确切的版本/设置Foo(Foo&&)
移动构造函数。这与操作符new或任何指针魔术无关。您的代码只需调用编译器为您定义的完全正常的复制/移动构造函数即可。就这样。这种行为是标准规定的。一个不可复制的类(至少在标准的原始版本中)实际上是毫无价值的。
如果不希望自动生成副本构造函数,通常的技术是将它们定义为已删除或私有。
还请注意,在某些情况下,编译器有权从程序中实际删除整个对象,即使通常不应该。如果在Foo构造函数中使用指针到Foo设置了hijinks,则必须在所有构造函数和析构函数中严格处理它们,这意味着必须编写自己的复制/移动构造函数、析构函数和赋值运算符,否则编译器运行对象时将成为裁剪器。
发布于 2014-08-02 03:19:29
您正在观察的构造函数是复制构造函数。每个类都有一个副本构造函数。如果未在类定义中声明任何副本构造函数,则将隐式为您声明副本构造函数。
隐式声明的复制构造函数的特定签名取决于类定义,即基础和成员--通常是表单X::X(X const &)
,但必要时可以是X::X(X &)
或X::X(X volatile &)
。异常规范尽可能严格。隐式声明的复制构造函数的定义通常由复制基和成员组成,但在某些情况下可以定义为删除(例如,如果您声明了一个移动构造函数)。
(在C++的未来版本中,如果声明副本或移动赋值运算符,则隐式声明的复制构造函数将被定义为“删除”。在C++11和C++14中,它是默认的。)
https://stackoverflow.com/questions/25094217
复制相似问题