Рекомендуются ли операторы копирования с идиомой копирования и обмена и проверкой самостоятельного назначения?
Здесь вы можете увидеть реализацию оператора присваивания копирования с самопроверкой проверки:
String & operator=(const String & s)
{
if (this != &s)
{
String(s).swap(*this); //Copy-constructor and non-throwing swap
}
// Old resources are released with the destruction of the temporary above
return *this;
}
Это хорошо для самостоятельного назначения, но плохо для производительности:
- как каждый раз, когда он проверяет, как будто утверждение (я не знаю, насколько оно будет оптимальным, учитывая прогноз ветвления)
- Также мы теряем здесь копию elision для аргументов rvalue
Так что я до сих пор не понимаю, буду ли я реализовывать std::vector
"s operator=
как бы я это реализовал.
2 ответа
Да, этот код является излишним. И это правда, что это вызывает лишнюю ненужную ветвь. При правильной семантике подкачки и перемещения следующее должно быть намного более производительным:
String& String::operator=(String s) { // note passing by value!
std::swap(s, *this); // expected to juggle couple of pointers, will do nothing for self-assingment
return *this;
}
Также обратите внимание, что выгоднее принимать аргумент по значению.
как каждый раз, когда он проверяет, как будто утверждение (я не знаю, насколько оно будет оптимальным, учитывая прогноз ветвления)
Я думаю, что вы попали в круг преждевременной оптимизации здесь.
Проверка на самостоятельное назначение -> самостоятельное назначение не требуется, если вы правильно написали код -> почему бы не написать swap
явно если ты это имеешь ввиду? -> мы вернулись на круги своя
Реально я бы просто внедрил Allocator и не беспокоился об этом.
Также мы теряем здесь копию elision для аргументов rvalue
Я так не думаю.
#include <iostream>
#define loud(x) std::cout << x << "\n";
struct foo
{
foo() { loud("default") }
~foo() { loud("destruct") }
foo(const foo&) { loud("copy") }
foo(foo&&) { loud("move") }
foo & operator=(const foo & s)
{
if (this != &s)
{
loud("copy assign")
}
return *this;
}
};
int main()
{
foo f;
foo g;
g = f;
}
Выходы:
default
default
copy assign
destruct
destruct
Это с -fno-elide-constructors
,
Вы утверждаете, что ветка может быть проблемой, но вывод сборки для -O2
показывает, что GCC даже не испускает код для operator=
и просто выводит "copy assign"
строка напрямую. Да, я понял, что у меня есть упрощенный пример, но это действительно неправильный конец стопки.