Я создаю класс типа цепочки, такой как маленький пример ниже. Похоже, что при объединении функций-членов вызывается конструктор копирования. Есть ли способ избавиться от вызова конструктора копирования? В моем примере с игрушкой, приведенным ниже, очевидно, что я имею дело только с временными, и поэтому «должно» (возможно, не по стандартам, но логически) быть правомочным. Второй лучший вариант - скопировать elision - вызывать конструктор перемещения, но это не так.
class test_class {
private:
int i = 5;
public:
test_class(int i) : i(i) {}
test_class(const test_class& t) {
i = t.i;
std::cout << "Copy constructor"<< std::endl;
}
test_class(test_class&& t) {
i = t.i;
std::cout << "Move constructor"<< std::endl;
}
auto& increment(){
i++;
return *this;
}
};
int main()
{
//test_class a{7};
//does not call copy constructor
auto b = test_class{7};
//calls copy constructor
auto b2 = test_class{7}.increment();
return 0;
}
Изменить: некоторые разъяснения. 1. Это не зависит от уровня оптимизации. 2. В моем реальном коде у меня есть более сложные (например, выделенные в куче) объекты, чем целые
auto b = test_class{7};
не вызывает конструктор копирования, потому что он действительно эквивалентен,test_class b{7};
а компиляторы достаточно умны, чтобы распознать этот случай и поэтому могут легко исключить любое копирование. То же самое не может быть сделано дляb2
.std::cout
) в вашем экземпляре ctor? Без этого копия должна быть оптимизирована.Ответы:
Частичный ответ (он не
b2
создается на месте, но превращает конструкцию копии в конструкцию перемещения): Вы можете перегрузитьincrement
функцию-член в категории значений связанного экземпляра:Это вызывает
переместить-построить,
b2
потому чтоtest_class{7}
это временно, и&&
перегрузкаtest_class::increment
называется.Для истинной конструкции на месте (т.е. даже конструкции перемещения) вы можете превратить все специальные и не специальные функции-члены в
constexpr
версии. Затем вы можете сделатьи вы ни ход, ни копирование конструкции, чтобы заплатить. Это, очевидно, возможно для простого
test_class
, но не для более общего сценария, который не учитываетconstexpr
функции-члены.источник
b2
немодифицируемым.constinit
был бы путь туда.this
же самое, что иconst
функции-членыПо сути, назначение ссылки на значение требует вызова конструктора, то есть копии или перемещения . Это отличается от copy-elision, когда с обеих сторон функции известно, что это один и тот же отдельный объект. Также ссылка может ссылаться на общий объект, очень похожий на указатель.
Самый простой способ, вероятно, - сделать конструктор копирования полностью оптимизированным. Настройка значения уже оптимизирована компилятором, это просто то,
std::cout
что нельзя оптимизировать.(или просто удалите и конструктор копирования и перемещения)
живой пример
Поскольку ваша проблема связана со ссылкой, решение, вероятно, не возвращает ссылку на объект, если вы хотите прекратить копирование таким способом.
Третий метод - в первую очередь просто полагаться на исключение копирования - однако это требует перезаписи или инкапсуляции операции в одну функцию и, таким образом, полностью исключает проблему (я знаю, что это не то, что вы хотите, но это может быть решение для других пользователей):
Четвертый метод использует вместо этого перемещение, либо вызывается явным
или как видно в этом ответе .
источник