Я подозреваю, что я смутно знаю причину того, что я наблюдаю, но я хотел бы получить подтверждение или исправление и некоторое объяснение этому.возвращение rvalue? Или: почему конструктор копирования вызывается на `return <expression>`?
Я следующий код:
template <class T>
class C
{
public:
C() = default;
C(const C& rhs) : mem(rhs.mem)
{
std::cerr << "copy" << "\n";
}
// does not call copy constructor twice
// friend C operator<<(C& src, unsigned shift)
// {
// std::cerr << 1 << "\n";
// C tmp(src);
// std::cerr << 2 << "\n";
// tmp <<= shift;
// std::cerr << 5 << "\n";
// return tmp;
// }
// does call copy constructor twice
friend C operator<<(C& src, unsigned shift)
{
std::cerr << 1 << "\n";
C tmp(src);
std::cerr << 2 << "\n";
return (tmp <<= shift);
}
friend C& operator<<=(C& src, unsigned shift)
{
std::cerr << 3 << "\n";
src.mem <<= shift;
std::cerr << 4 << "\n";
return src;
}
T mem;
};
int main()
{
C<int> c1;
c1 << 3;
}
У меня есть две версии C<T>::operator<<(C<T>, unsigned)
разница является один возвращает результат выражения:
return (tmp <<= shift);
другой возвращает переменную:
return tmp
До сих пор я думал, что эти две функции были бы идентичны семантически и один с return (tmp <<= shift);
просто быть лучше стиль, как return a + 1
будет лучше, чем стиль int ret = a + 1; return ret
. Это, по-видимому, не так и, вероятно, справедливо только для атомных типов данных. Выход версии с return (tmp <<= shift);
выглядит следующим образом:
1
copy
2
3
4
copy
выход другого, как это:
1
copy
2
3
4
5
Является ли мое предположение верно, что Infact return (tmp <<= shift);
не возвращает tmp
после вызова <<=
на ITM, но скорее создать новый объект в качестве копии tmp
после того, как был вызван <<=
?
Вы должны действительно протестировать различные уровни оптимизации, если вы собираетесь тестировать, когда вызывается или когда вы создаете конструктор копирования. Вывод может быть совершенно другим в зависимости от компилятора, оптимизации компилятора и т. Д. – PaulMcKenzie