Страницы

Поиск по вопросам

вторник, 28 января 2020 г.

В чем отличие & от && на примере конструктора копирования и конструктора переноса?

#cpp #cpp11 #конструктор #семантика


Допустим, у нас есть класс с обычным конструктором:

   class SomeClass { 
    int size; 
    int *element; 
   public: 
    SomeClass(int i) { //обычный конструктор
     size = i; 
     element = new int[size]; 
     } 
    }; 


И предположим, что я добавил туда конструктор копирования и конструктор перемещения
(переноса):

SomeClass( SomeClass &&other ) { //конструктор перемещения
 size = other.size; 
 element = other.element; 
 other.size = 0; 
 other.element = nullptr; 
} 

SomeClass( SomeClass &other ) { //конструктор копирования
 size = other.size; 
 element = other.element; 
 other.size = 0; 
 other.element = nullptr; 
} 

int main()  {
 SomeClass a1(5);
 SomeClass a2(a1); //вызов конструктора копирования
 SomeClass a3 = move(a1); //вызов конструктора переноса
}


Здесь один нюанс: конструктор копирования не будет копировать, он тоже будет выполнять
перенос.

В чем тогда отличие? Если фактически происходит одно и тоже. Code::Blocks выдает
разницу в секунду. Думаю, тогда вопрос встает между использованием & и &&.

Я знаю, что второе - это ссылка на r-value, и что она позволяет обратиться к ресурсам
объекта. Но ведь в обоих случая создается новый объект. В чем тогда профит?
    


Ответы

Ответ 1



Конструктор перемещения это чисто конвенциональная конструкция(так же как и конструктор копирования, собственно), поэтому никто не мешает делать в любом конструкторе всё, что заблагорассудится. Другое дело, что программист, использующий Ваш класс, будет ожидать перемещения от конструктора перемещения и никак не будет ожидать такого подвоха от конструктора копирования. В том числе и поэтому, конструктор копирования всегда объявляется с константным аргументом, а не как у Вас. Ещё раз, конструкторы имеют свои названия исходя из того, что они делают по умолчанию(т.е. тогда, когда их генерирует компилятор). Соответственно, программист тоже должен делать так, как делается по умолчанию, а не придумывать реализацию, которая больше похожа на саботаж, чем на что-либо другое. Исходя из всего вышесказанного: Ваш вопрос не имеет смысла. Отличным примером перемещающего конструктора копирования является std::auto_ptr. Все мы знаем его судьбу.

Ответ 2



Существует несколько категорий выражений, наболее известные - это "rvalue" и "lvalue". Переменная с типом T&& может принимать только r-value выражение, переменная с типом T& может принимать только не константные l-value выражения. Совершенно не важно, что это за переменная - агрумент конструктора или нет. Соответственно разница между SomeClass( SomeClass &&other ) и SomeClass( SomeClass &other ) - только в том, что первый будет вызываться только для r-value выражений, а второй - только для неконстантных l-value выражений. При этом ни один из них не может принимать const SomeClass &. Что именно делают конструкторы - никому не важно, то что у них одинаковый код - это тоже не важно. Единственное отличие - это категории выражений, которые они могут принимать.

Ответ 3



Ваш конструктор копирования изменяет состояние объекта, с которого делается копия. Соответственно, такую операцию уже нельзя в полной мере назвать копированием. Правильная сигнатура конструктора копирования такая: SomeClass( const SomeClass &other )

Ответ 4



В чем тогда профит? Rvalue ссылки позволяют программистам избегать логически ненужного копирования и обеспечивать возможность идеальной передачи (perfect forwarding). Прежде всего они предназначены для использования в высоко производительных проектах и библиотеках.

Комментариев нет:

Отправить комментарий