Во-первых, зачем здесь () после MyObject? Во-вторых, что ты потом будешь делать с этим объектом? Как к нему обращаться? Если это чисто хеадер, то что мешает написать
Он, видимо, про вызов метода в коде — someMethod(MyObject), someMethod(MyObject{}), someMethod(MyObject()) при явном или нет дефолтном конструкторе, bool перед не нужен. Вполне делается с помощью const lvalue reference / mutable rvalue reference (C++11).
Ну тогда пусть будет const& вместо &. Таким образом можно принимать ссылок на временные («анонимные») объекты сколько угодно, вплоть до возможности строить сложные expressions — someMethod(someCopy(SomeCon1(SomeCon2(...), SomeCon3(...)))) (везде подразумевается const& у аргументов, чтобы без копирований).
Во, можешь мне обьяснить, что это за фишка такая. И как она работает?
Думаю понятно зачем оно нужно, но на всякий случай - иногда выгоднее просто «отдать» значение, чтобы не копировать. Скажем, передаём параметр в конструктор - внутри он сохраняется (копируется) всё равно. Это примерно как передача unique_ptr (передача владения).
Работает довольно просто. Например, есть у нас свой класс для строк:
class mega_string
{
char *m_data;
size_t m_size;
};
Но бывают случаи, когда значение конструируется где-то заранее и потом нафиг не нужно. Если бы у нас было только копирование, то мы бы лишний раз копировали, потом тут же удаляли оригинал, так как он уже не нужен. В этом случае, выгоднее не копировать, а «отдать» данные:
То есть принимать && это всё равно что принимать & (не const), только с той разницей, что в случае & мы можем передать только lvalue, то есть, допустим, некую переменную x связанную (слева, т.е. объявлением с конструктором) с куском стека вызывающей функции — принимающая принимает ссылку (фактически указатель) на кусок стека вызывающей функции, может этот кусок изменять, может вернуть ссылку на него обратно. Теперь, если мы передаём rvalue, например временный объект, например в случае someFunc(string1 + string2), то этот временный объект (от string1 + string2) тоже (допустим!) существует на стеке вызывающей функции, но не связан с какой-либо переменной (не l, а r, то есть просто выражение дающее временный объект), прилетит тот же указатель на кусок стека, но он виден только принимающей функции — если это конструктор копирования, то ему не нужно ничего копировать, объект уже есть, он уникально наш, можно его просто подобрать (поэтому move); в случае просто функции или метода — можно его подобрать и вернуть (обычную) ссылку на него вызывающей стороне — так мы можем этот временный объект превратить в обычное lvalue.
Это примерно про && в аргументах конструкторов, функций и методов. Ещё её можно возвращать — метод временного объекта может возвращать && на часть объекта, так что вызывающий будет подбирать (move) именно её.
Для примеров передачи и возвращения в/из обычных функций (собирать с -O0, чтобы рассмотреть адреса без лишних оптимизаций):
#include <cstdio>
#include <string>
#include <memory>
struct A {
std::string label;
int x;
void print() const {
printf("A{%s}{%d}[%p]\n", label.c_str(), x, this);
}
};
A const& f(A const& x) {
printf("f-const on ");
x.print();
return x;
}
A& f(A&& x) {
printf("f-mut on ");
x.print();
x.x += 1;
return x;
}
A&& g(A&& x) {
printf("g on ");
x.print();
x.x += 2;
return std::move(x);
}
A h(A const& x) {
printf("h on ");
x.print();
return A{"copy-tmp", x.x + 3};
}
int main() {
int stack_starts;
printf("main stack starts at %p\n", &stack_starts);
// main stack starts at 0x7fff341008ec
A lvalue{"lvalue1", 1};
lvalue.print();
// A{lvalue1}{1}[0x7fff341008d8]
f(lvalue).print();
// f-const on A{lvalue1}{1}[0x7fff341008d8]
// A{lvalue1}{1}[0x7fff341008d8]
f(std::move(lvalue)).print();
// f-mut on A{lvalue1}{1}[0x7fff341008d8]
// A{lvalue1}{2}[0x7fff341008d8]
f(A{"tmp1", 2}).print();
// f-mut on A{tmp1}{2}[0x7fff341008b0]
// A{tmp1}{3}[0x7fff341008b0]
g(std::move(lvalue)).print();
// g on A{lvalue1}{2}[0x7fff341008d8]
// A{lvalue1}{4}[0x7fff341008d8]
g(A{"tmp2", 3}).print();
// g on A{tmp2}{3}[0x7fff34100898]
// A{tmp2}{5}[0x7fff34100898]
h(lvalue).print();
// h on A{lvalue1}{4}[0x7fff341008d8]
// A{copy-tmp}{7}[0x7fff34100880]
h(A{"tmp3", 4}).print();
// h on A{tmp3}{4}[0x7fff2aa25c50]
// A{copy-tmp}{7}[0x7fff2aa25c60]
lvalue.print();
// A{lvalue1}{4}[0x7fff341008d8]
}
DarkEld3r
Спасибо всем за ценную информацию.
Я так понял, что это передача параметра по ссылке, но при этом мы говорим, что функция деструктивна для этого параметра.
это передача параметра по ссылке, но при этом мы говорим, что функция деструктивна для этого параметра
Да, только это же справедливо для обычного &. Как и && может быть const, как &, тогда нет деструктивности. Разница в том, что & работает с нормальными объектами (в т.ч. деструктивно) и НЕ работает со временными (кроме как по const&, но оно не используется при наличии версии с &&), а && работает со временными (тоже в т.ч. деструктивно) и НЕ работает с обычными (если только не сделать им std::move) — перегрузив функцию можно выбирать что делать с обычными (они сконструированы каким-то владельцем), а что со временными (нет владельца). Относительно объектов — может нам не нужна семантика копирования вообще, тогда сам объект может не реализовывать copy семантику, только move в своих конструкторах, тогда будет возможность агрегировать/принимать/возвращать не copyабельный, но movабельный объект.