我正在研究复制省略和 RVO/NRVO。当我使用 -fno-elide-constructors
运行 g++ 时,我看到 c++11 和 c++17 的行为不同。
我了解 c++17 在某些情况下强制使用 RVO。我假设下面的内容算作 NRVO(除非编译器首先也消除了命名变量y
?)
struct rvo
{
rvo () : val {0} { std::cout << "Default Constructor" << std::endl;};
~rvo (){ std::cout << "Destructor" << std::endl; };
rvo(const rvo& in){ std::cout << "Copy Constructor" << std::endl; }
rvo(rvo&& in){ std::cout << "Move Constructor" << std::endl; }
double val;
};
rvo f1(rvo& x){
rvo y {x};
y.val++;
return y;
}
int main()
{
rvo A{};
rvo B {f1(A)};
return 0;
}
在没有附加标志的情况下编译时的输出符合预期
Default Constructor
Copy Constructor
Destructor
Destructor
使用 -fno-elide-constructors
和 --std=c++11
编译时,输出为
Default Constructor
Copy Constructor
Move Constructor
Destructor
Move Constructor
Destructor
Destructor
Destructor
这很好,因为正在创建临时文件。
我的问题是,当我使用 -fno-elide-constructors
和 --std=c++17
进行编译时,它消除了其中一个移动。
Default Constructor
Copy Constructor
Move Constructor
Destructor
Destructor
Destructor
看起来它正在消除临时返回变量,并将函数变量y
移回main中的B
。即使我已经关闭了省略。是否将其视为强制性 RVO 还是我误解了一些基本内容?
我找到了这个例子,RVO/NRVO can not be disabled in C++17 in Clang++?但那个显然是 RVO,而我认为我的示例是 NRVO,因此不是强制性的。
如果有人能证实,非常感谢。
最佳答案
这是因为来自c++17有mandatory copy elision相反,对象B
是直接从返回值创建f(A)
,因此不使用移动构造函数或拷贝ctor 以及输出。
这可以从copy elision documentation看出:
Under the following circumstances, the compilers are required to omit the copy and move construction of class objects, even if the copy/move constructor and the destructor have observable side-effects. The objects are constructed directly into the storage where they would otherwise be copied/moved to. The copy/move constructors need not be present or accessible:
- In the initialization of an object, when the initializer expression is a prvalue of the same class type (ignoring cv-qualification) as the variable type:
T x = T(T(f())); // only one call to default constructor of T, to initialize x
关于c++ - NRVO。关闭省略。 C++11 与 C++17,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75546216/