Clang 在析构函数中修改 return 值?
Clang modifies return value in destructor?
在尝试编写一个 class 来计算调用它的构造函数和析构函数之间的持续时间时,我 运行 我认为是 clang 中的一个错误。 (编辑:这不是错误;它是实现定义的复制省略)
下面的 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;
}
使用 clang 7.0.0 编译时,输出为:
some heavy calculation here
duration: 21642
function: 21642
而对于 g++ 8,输出是
some heavy calculation here
duration: 89747
function: 0
在这种情况下,我确实喜欢 clangs 行为,但从我在其他地方发现的情况来看,应该在析构函数 运行.
之前复制 return 值
这是 Clang 的错误吗?或者这取决于(实现定义?)return 价值优化?
无论 timer
中的 duration d
是指针还是引用,行为都是相同的。
--
我知道编译器的不一致可以通过改变 f
来解决,这样计时器的范围在 return 之前结束,但这不是重点。
timer::duration f(){
timer::duration d{};
{
timer _(d);
std::cerr << "some heavy calculation here" << std::endl;
}
return d;
}
简短回答:由于 NRVO,程序的输出可能是 0
或实际持续时间。两者都有效。
背景先看:
- What are copy elision and return value optimization?
指南:
- 避免修改 return 值的析构函数。
例如,当我们看到以下模式时:
T f() {
T ret;
A a(ret); // or similar
return ret;
}
我们需要问自己:A::~A()
是否以某种方式修改了我们的 return 值?如果是,那么我们的程序很可能有错误。
例如:
- 销毁时打印 return 值的类型很好。
- 一种在销毁时计算 return 值的类型不。
在尝试编写一个 class 来计算调用它的构造函数和析构函数之间的持续时间时,我 运行 我认为是 clang 中的一个错误。 (编辑:这不是错误;它是实现定义的复制省略)
下面的 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;
}
使用 clang 7.0.0 编译时,输出为:
some heavy calculation here
duration: 21642
function: 21642
而对于 g++ 8,输出是
some heavy calculation here
duration: 89747
function: 0
在这种情况下,我确实喜欢 clangs 行为,但从我在其他地方发现的情况来看,应该在析构函数 运行.
之前复制 return 值这是 Clang 的错误吗?或者这取决于(实现定义?)return 价值优化?
无论 timer
中的 duration d
是指针还是引用,行为都是相同的。
--
我知道编译器的不一致可以通过改变 f
来解决,这样计时器的范围在 return 之前结束,但这不是重点。
timer::duration f(){
timer::duration d{};
{
timer _(d);
std::cerr << "some heavy calculation here" << std::endl;
}
return d;
}
简短回答:由于 NRVO,程序的输出可能是 0
或实际持续时间。两者都有效。
背景先看:
- What are copy elision and return value optimization?
指南:
- 避免修改 return 值的析构函数。
例如,当我们看到以下模式时:
T f() {
T ret;
A a(ret); // or similar
return ret;
}
我们需要问自己:A::~A()
是否以某种方式修改了我们的 return 值?如果是,那么我们的程序很可能有错误。
例如:
- 销毁时打印 return 值的类型很好。
- 一种在销毁时计算 return 值的类型不。