Clang修改析构函数中的返回值?

Rag*_*nar 9 c++ clang++

在尝试编写一个类,调用它的构造函数和析构函数之间的持续时间时,我遇到了我认为是clang中的错误.(编辑:这不是一个bug;它是实现定义的副本省略)

timer下面的结构保存一个指向作为引用传入的持续时间对象的指针,并将范围的持续时间添加到此.

#include <iostream>
#include <chrono>
struct timer {
    using clock      = std::chrono::high_resolution_clock;
    using time_point = clock::time_point;
    using duration   = clock::duration;
    duration* d_;
    time_point start_;
    timer(duration &d) : d_(&d), start_(clock::now()) {}
    ~timer(){
        auto duration = clock::now() - start_;
        *d_ += duration;
        std::cerr << "duration: " << duration.count() << std::endl;
    }
};

timer::duration f(){
    timer::duration d{};
    timer _(d);
    std::cerr << "some heavy calculation here" << std::endl;
    return d;
}

int main(){
    std::cout << "function: " << f().count() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

使用clang 7.0.0编译时,输出为:

some heavy calculation here
duration: 21642
function: 21642
Run Code Online (Sandbox Code Playgroud)

而对于g ++ 8,输出是

some heavy calculation here
duration: 89747
function: 0
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我确实喜欢clangs行为,但是从我在别处找到的内容中,返回值应该在析构函数运行之前复制.

这是Clang的错误吗?或者这取决于(实现定义?)返回值优化?

无论duration din timer是指针还是引用,行为都是相同的.

-

我确实意识到编译器的不一致性可以通过更改来解决,f以便计时器的范围在返回之前结束,但这不在此处.

timer::duration f(){
    timer::duration d{};
    {
        timer _(d);
        std::cerr << "some heavy calculation here" << std::endl;
    }
    return d;
}
Run Code Online (Sandbox Code Playgroud)

Aco*_*orn 5

简答:由于NRVO,程序的输出可能是0或实际持续时间.两者都有效.


有关背景信息,请参阅:

指南:

  • 避免使用修改返回值的析构函数.

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

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

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

例如:

  • 在销毁时打印返回值的类型很好.
  • 计算破坏时的返回值的类型不是很好.