В C++ не всегда бывает так, что знак = означает вызов оператора присваивания, из-за чего народ начинает путаться.
Я нашла в comp.lang.c++.moderated большой хороший пример, может пригодится кому.
class B { ... };
class A
{
...
public:
// Constructor
A() { ... }
// Copy constructor
A(const A& a_obj) { ... }
// Constructor overloading
A(const B& b_obj) { ... }
...
A& operator=(const A& a_src) { ... }
...
};
// Примеры:
A a1; // конструктор вида A()
A a2(a1); // конструктор копирования A(a1)
A a3 = a2; // конструктор копирования A(a2)
B b;
A a4(b); // перегруженный конструктор A(b)
A a5 = b; // перегруженный конструктор A(b)
a1 = a5; // operator=(const A&) то есть operator=(a5)
a2 = b; // Шаг1: создается временный объект класса а A
// с помощью конструктора вида A(b),
// Шаг2: -> operator=(const A&) то есть operator=(A(b))
Если будете экспериментировать, не забудьте выключить оптимизацию.

Atom feed
15 коммент.:
Я бы еще добавил про последнюю строчку:
там - как и описано Алёной - происходят не очевидные с первого взгляда вещи, что есть не очень хорошо,
в связи с этим, например, Гугл рекомендует конструкторы с одним параметром объявлять как explicit, чтобы такие вещи явно прописывались в коде и не прятали за собой сюрпризов - ведь можно подумать, что скорее всего тут сработатывает оператор копирования
Ну, товарищи знакомые с языками вроде Erlang знают, что оператор присваивания не то, чем кажется :) Точнее, что его вообще может не быть.
Не знаю как кому но меня это в заблуждение никогда не вводило:) ИХМО это такие вещи в которых путатцо нильзя.
К слову, конструктор такого типа
A(const B& b_obj) { ... }
называется конструктором преобразования
Не совсем корректный пример!!!
// да. конструктор A()
A a1;
// это - вызов explicit
// конструктора A(const A &),
// который есть конструктор
// копирования
// *по совместительству*
A a2(a1);
А то что rikkitikkitavi сказал насчет explicit- так любая декларация объекта- это вызов конструктора либо со знаком "=" либо explicit- со скобочками, либо без всего.
В моем понимании- существует "нативный" контекст конструктора копирования- это вызов, который генерируется компилятором для передачи значений по стеку. Но в контексте декларации- это обычный конструктор.
А как происходит у вас на практике?
То есть стараетесь вы объявлять конструкторы копирования explicit?
Или же за этим четко не следите?
2 Roman: честно говоря, Google C++ Style Guide я прочитал совсем недавно, с тех пор стараюсь так писать, а до этого сам как-то не думал
с гуглом я согласен - когда вы работаете совместно в большой команде, когда вы работаете с сотнями классов, большей частью вообще не вами написанных, то начинаешь сильно ценить ясность и читабельность кода
все мои слова относятся в первую очередь к конструкторам "преобразования"
не глядя в объявления классов вы можете сказать сколько объектов класса А будет создано
B b;
A a;
a = b;
?
правильно, не можете
глядя на этот код большинство людей ожидает что выполнится оператор копирования
а теперь представьте, что по каким-то причинам создание временного объекта критично и/или бажно
сколько времени вы потратите на поиск этого
примерно такие доводы у гугла, почитайте
В целом очевидные вещи но, если копаешь чужой код то это просто ад. (Вспомниаю кучу таких классов в Вангерах)
2 rikkitikkitavi
Большое спасибо за наводку на Google C++ Style Guide :)
Если я ничего не путаю, поведение компилятора в случае со строчкой
A a2 = a1;
зависит от "настроения" компилятора и может интерпретироваться либо как вызов конструктора копирования, либо как вызов конструктора по умолчанию и последующего вызова оператора присваивания.
согласно стандарту, эта строчка должна интерпретироваться компилятором как вызов конструктора копирования
Чтобы избежать сюрпризов, нужно все конструкторы, операторы приведения типов и операторы присваивания делать согласованными.
Тогда нет особой разницы (кроме просадки производительности), что за цепочка там сработала, да ещё с учётом RVO всяческого.
Либо бить по рукам с помощью explicit или private.
Присоединяюсь к благодарностям за Google C++ code style))
По-моему, сложнее всего для новичков отличить случай вызова конструктора с аргументом от случая с последовательным вызовом конструктора с аргументом в правой части присваивания и, собственно, оператора присваивания.
P.S. Алене спасибо за пост и за помощь по этому вопросу :) Также присоединяюсь к благодарностям за Google C++ Style Guide.
Отправить комментарий