c++ - 当析构函数调用自动变量修改函数返回值时,MSVC14.1和gcc8.3之间观察到差异

标签 c++ c++14

考虑以下内容(使用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相同。
我不认为这是悬而未决的引用未定义行为(因为retfoo之前声明),但是这可能是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/

相关文章:

c++ - `auto` 关键字在 lambda 函数中如何工作?

c++ - std::list - 迭代器是否在移动时失效?

java - 在游戏中用java检测鼠标点击

c++ - 为什么 "return (str);"在 C++ 中推导的类型与 "return str;"不同?

c++ - 无论我使用什么输入/窗口处理程序,OpenGL 代码都可以工作吗?

c++ - Canny 边算法只需要一条边

c++ - 当我从虚拟基派生 D 时,为什么 VS2015 中的 sizeof(D) 增加了 8 个字节?

c++ - 使用模板包进行扩展

c++ - 从所有列出的文件和子目录更改目录

c++ - 在 LLVM 模块上运行标准优化传递