在 RAII 构造中修改 RVO 值是否安全?

Bri*_*uez 5 c++ destructor raii copy-elision rvo

考虑以下程序:

#include <functional>
#include <iostream>

class RvoObj {
  public:
    RvoObj(int x) : x_{x} {}
    RvoObj(const RvoObj& obj) : x_{obj.x_} { std::cout << "copied\n"; }
    RvoObj(RvoObj&& obj) : x_{obj.x_} { std::cout << "moved\n"; }

    int x() const { return x_; }
    void set_x(int x) { x_ = x; }

  private:
    int x_;
};

class Finally {
  public:
    Finally(std::function<void()> f) : f_{f} {}
    ~Finally() { f_(); }

  private:
    std::function<void()> f_;
};

RvoObj BuildRvoObj() {
    RvoObj obj{3};
    Finally run{[&obj]() { obj.set_x(5); }};
    return obj;
}

int main() {
    auto obj = BuildRvoObj();
    std::cout << obj.x() << '\n';
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

clang 和 gcc ( demo ) 输出都5没有调用复制或移动构造函数。

这种行为是否得到 C++17 标准的明确定义和保证?

Aco*_*orn 3

简短回答:由于 NRVO,程序的输出可能是35。两者都有效。


有关背景,请先参阅:

指导方针:

  • 避免修改返回值的析构函数。

例如,当我们看到以下模式时:

T f() {
    T ret;
    A a(ret);   // or similar
    return ret;
}
Run Code Online (Sandbox Code Playgroud)

我们需要问自己:是否以A::~A()某种方式修改了我们的返回值?如果是,那么我们的程序很可能有错误。

例如:

  • 在销毁时打印返回值的类型就可以了。
  • 在销毁时计算返回值的类型是不好的。

[来自/sf/answers/3819625631/ ]


归档时间:

查看次数:

126 次

最近记录:

6 年,2 月 前