C++ - 为什么在没有明显的构造函数匹配时编译此代码?
C++ - why does this code compile when there's no obvious constructor match?
请考虑以下代码:
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))));
为什么使用clang编译这些示例时没有警告,甚至使用-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)); }
编译器自动生成复制构造函数Foo(const Foo&)
,并可能根据Foo(Foo&&)
的确切版本/设置移动构造函数。这与操作符new或任何指针魔法无关。您的代码只需调用编译器为您定义的一个完全正常的复制/移动构造函数。这是所有。这种行为是标准强制要求的。一个不可复制的类(至少在标准的原始版本中)实际上是毫无价值的。
如果不希望自动生成复制构造函数,通常的方法是将它们定义为已删除或私有。
还要注意,编译器在某些情况下有权从程序中删除整个对象,尽管通常情况下它不应该这样做。如果你在Foo构造函数中使用指向Foo的指针集合,你必须在所有的构造函数和析构函数中严格地处理它们,这意味着你必须编写自己的复制/移动构造函数、析构函数和赋值操作符,否则当编译器省略一个对象时,你将会失败。
您正在观察的构造函数是复制构造函数。每个类都有一个复制构造函数。如果没有在类定义中声明任何复制构造函数,则复制构造函数是为您隐式声明的。
隐式声明的复制构造函数的特定签名取决于你的类定义,即基类和成员—它的格式通常为X::X(X const &)
,但必要时也可以是X::X(X &)
或X::X(X volatile &)
。异常规范是尽可能严格的。隐式声明的复制构造函数的定义通常由复制基和成员组成,但在某些情况下(例如,声明move构造函数),它可以定义为删除。
(在以后的c++版本中,如果声明了copy或move赋值操作符,则隐式声明的复制构造函数将被定义为deleted。在c++ 11和c++ 14中,它是默认的。)
- 在Linux for Windows上编译C++代码时出错
- 在编译C++代码(具有dlib和opencv)到WASM时面临问题
- 在程序中编写脚本来编写和编译代码
- 未定义的引用 .. 使用 OpenCV 编译 C++ 代码时,从命令行
- 在macos上编译代码的未解析符号
- 使用个人C++库编译代码时,与头文件一起使用时会中断
- 使用指针编译代码后,.cpp文件将变为随机字符
- VS Express 无法正确编译代码(?
- 如何在Ubuntu中使用Visual Studio代码编译C++代码
- 使用 Android NDK 使用 clang++ 编译C++代码时对"_Unwind_Resume"的未定义引用
- 无法使用两个包装不同下一层的ssl_stream编译代码
- 编译代码时"[Warning] extra tokens at end of"
- 无法编译代码,因为它已在 C++11 中弃用
- 如何在 Azure 应用服务中使用 cl.exe 编译 C++ 代码并生成可执行文件
- 如何调试编译 c++ 代码的 bazel?
- 为什么在使用转换构造函数编译代码时需要 const 复制构造函数?
- 编译 C++ 代码后尺寸较大
- 使用用 C++ 和 DDS 编写的 CMAKE 编译代码
- 编译代码时如何不制作二进制文件?
- 如何使用所有其他文件信息来编译代码,例如HAAR级联训练的权重的XML文件