Mic*_*ake 1 c++ compiler-optimization
有人说,在大多数情况下,编译器比人类更聪明,并且会优化很多我们无法明确执行的东西。我想知道编译器是否对此进行了优化。下面的代码有有趣的结果,但没有错误。但有一个严重的问题。
//will this move or copy construct?
#include <iostream>
class A
{
public:
A()
{
std::cout << "Constructed A.\n";
}
~A()
{
std::cout << "A destroyed.\n";
}
};
class B
{
private:
A m_A;
public:
B(A someA):m_A{someA}
{
}
};
int main()
{
B oneB{A()};
return 0;
}
Run Code Online (Sandbox Code Playgroud)
此代码使用 Clang++ 13.0.1 在 Windows 10 上打印-fexceptions -O3 -Wall -g -std=c++20 -v -c
Constructed A.
A destroyed.
A destroyed.
Run Code Online (Sandbox Code Playgroud)
为什么A被销毁了两次但只被构造了一次?B即使使用常量引用构建时也会发生这种情况。这真是太荒谬了。我仍在学习 C++,从未参与过任何项目或其他任何事情。我想问一些我在网上学习时感到困惑的事情。
为什么A被销毁了两次但只被构造了一次?
A第二次被破坏的和第一次被破坏的不一样A。您可以通过向类中添加复制构造函数来确认/验证这一点,A如下所示。复制构造函数将用于m_A在m_A{someA}成员初始值设定项列表中进行初始化。
class A
{
public:
//other members as before
//copy constructor added
A(const A&)
{
std::cout<<"copy ctor"<<std::endl;
}
};
Run Code Online (Sandbox Code Playgroud)
添加复制构造函数后,程序的输出将如下所示:
Constructed A.
copy ctor
A destroyed.
A destroyed.
Run Code Online (Sandbox Code Playgroud)
请注意,您使用的 C++20 具有强制复制 elison(从 C++17 及以上版本)。这意味着当您写道:
B oneB{A()};
Run Code Online (Sandbox Code Playgroud)
在C++20(&C++17)中,没有创建临时对象,直接创建参数, A someA无需B::B(A)复制任何临时对象。
但在 C++17 之前,存在非强制复制 elison。这意味着A将创建一个临时对象,该对象将被复制/移动到名为 的参数someA。但编译器被允许省略这种复制/移动结构作为优化。
为了验证这一点,您可以将标志传递-fno-elide-constructors 给 C++11 或 C++14 中的编译器(这将告诉编译器不要进行涉及复制/移动构造的优化),您将看到这确实是发生的情况:如给定的演示链接所示:
使用 fno-elide-constructors 演示 C++11。
使用 C++11 和标志的程序的输出-fno-elide-constructors将是:
Constructed A.
copy ctor
copy ctor
A destroyed.
A destroyed.
A destroyed.
Run Code Online (Sandbox Code Playgroud)
请注意,该标志-fno-elide-constructors只会影响使用 C++17 之前版本标准的C++11 程序的输出。从 C++17 开始,将不再有对复制构造函数的额外调用。演示 C++17
你错了,它不是构造一次,而是构造两次:第一次作为临时对象,第二次当复制到 B 对象时。
但是,用于的复制构造函数是隐式生成的,并且不提供任何输出。显式添加一个,您将看到:
A(A const&)
{
std::cout << "Copied A.\n";
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
380 次 |
| 最近记录: |