Пытаясь написать класс, который бы умножил продолжительность между вызовом его конструктора и деструктора, я столкнулся с тем, что я считаю ошибкой в clang.(Правка: это не ошибка; это определенная реализацией копия elision)
Структура 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, но из того, что я нашел в другом месте, предполагается, что возвращаемое значение должно быть скопировано до запуска деструкторов.
Это ошибка с Clang?Или это зависит от (определенной реализации?) Оптимизации возвращаемого значения?
Поведение одинаково независимо от того, является ли duration d
в timer
указателем или ссылкой.
--
Я понимаю, что несоответствие компилятора можно устранить, изменив f
так, чтобы область действия таймера заканчивалась до возврата, но это здесь не относится к делу.
timer::duration f(){
timer::duration d{};
{
timer _(d);
std::cerr << "some heavy calculation here" << std::endl;
}
return d;
}