考虑以下内容(使用C++ 14编译)
#include <iostream>
#include <vector>
// Foo adds an element to a std::vector passed by reference
// on construction in the destructor
struct Foo {
Foo(std::vector<double>& v) : m_v(v){
}
~Foo(){
m_v.push_back(1.0);
}
std::vector<double>& m_v;
};
std::vector<double> bar(){
std::vector<double> ret;
Foo foo(ret);
return ret;
}
int main(){
std::cout << bar().size() << "\n";
}
在gcc8.3中,输出为1
,这意味着foo
的析构函数会对返回的 vector 产生影响。在MSVC14.1中,输出为
0
。您可以通过将Foo foo(ret);
行替换为{Foo foo(ret);}
(即通过强制作用域)来强制输出与gcc8.3相同。我不认为这是悬而未决的引用未定义行为(因为
ret
在foo
之前声明),但是这可能是MSVC14.1中的错误(如果这样,我将创建一个错误报告)。有人有确切消息么?参见https://ideone.com/pnxWuJ
最佳答案
我认为C++ 20标准的相关部分是[stmt.return],它表示
The copy-initialization of the result of the call is sequenced before the destruction of temporaries at the end of the full-expression established by the operand of the return statement, which, in turn, is sequenced before the destruction of local variables (8.7) of the block enclosing the return statement
因此,应首先构造函数调用的结果(返回值),然后销毁
foo
。由于返回值是在foo
的析构函数运行之前构造的,因此结果应为0。[class.copy.elision]部分说
When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the constructor selected for the copy/move operation and/or the destructor for the object have side effects.
因此,两个编译器都可以认为是正确的。
关于c++ - 当析构函数调用自动变量修改函数返回值时,MSVC14.1和gcc8.3之间观察到差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64977541/