LINUX.ORG.RU

Передача параметров в конструктор

 


0

4

Как лучше?

Как раньше: MyClassCtor(const DataType& value) : mValue(value)

или так: MyClassCtor(DataType value) : mValue(std::move(value))

?

Вангую анонима, который расскажем мне, куда нужно идти..

★★★★★

Последнее исправление: UVV (всего исправлений: 1)

не расскажу

у тебя же два разных конструктора, как их можно сравнивать в данном контексте? и вообще, что значит лучше?

anonymous
()

Сделай MyClassCtor(const DataType& value) : mValue(value) и MyClassCtor(DataType&& value) : mValue(std::forward(value)) Если уж так принципиально.

anonymous
()

Смотря что тебе нужно

MyClassCtor(const DataType& value) : mValue(value)

Cons: Здесь ты можешь передать только переменную, но не значение.
Pros: можешь передавать объект любого размера - стек используется по минимуму.

MyClassCtor(DataType value) : mValue(std::move(value))

Pros: можешь передавать и переменную и значение
Note: если передавать объект - я бы лишний раз убедился, что конструктор копирования и перемещение работает как надо
Cons: я бы не передавал так очень большие объекты

Всё не очень четко; для себя я решил, что простые типы я стараюсь передавать по значению, а объекты - по ссылке.

Kroz ★★★★★
()
Ответ на: комментарий от Kroz

Всё не очень четко; для себя я решил, что простые типы я стараюсь передавать по значению, а объекты - по ссылке.

Ну по сути тип несложный, там структура из двух std::string и парочки int'ов. Я ещё вот тут почитал http://stackoverflow.com/questions/17642357/c11-const-reference-vs-move-seman... , но не понял вот этот нюанс:

struct X
{
    double x;
    int i;
    char arr[255];
};

Then moving it won't be any faster than copying it (in fact, moving it would be the same thing as copying it).
Почему? Типа потому, что массиву ты не можешь сделать move?

UVV ★★★★★
() автор топика
Последнее исправление: UVV (всего исправлений: 1)
Ответ на: комментарий от anonymous

Как вариант, конечно. Спасибо.

Но разве во втором случае не должен быть MyClassCtor(DataType value) ?

UVV ★★★★★
() автор топика
Ответ на: комментарий от Kroz

Cons: Здесь ты можешь передать только переменную, но не значение.

Неправда твоя, временные объекты преобразовываются в константную ссылку. Cons другой: так как компилятор не знает, нужен ли ещё исходный объект, при последующей передаче в mValue, даже если для этого типа реализован конструктор перемещения, произойдёт копирование в конструкторе.

anonymous
()
Ответ на: комментарий от annulen

OK, ещё раз переосмыслил тот же тред, на который я сам ссылку и дал. Там то же решение.

UVV ★★★★★
() автор топика
Ответ на: комментарий от UVV

Решение с «универсальной ссылкой» может быть более красивым, если 1) ты готов перенести тело конструктора в заголовок; 2) ты не планируешь перегружать конструктор или наследоваться от этого класса (или ты должен очень хорошо понимать, какими граблями это чревато, чтобы не подставить лоб)

annulen ★★★★★
()
Ответ на: комментарий от annulen

И так и так можно. std::move кастит ссылку к ссылке на временный объект всегда, а forward кастит к временному только если эта переменная объявлена как р-валуе ссылка. Форвард, таким образом, более стоек к копипасте.

anonymous
()
Ответ на: комментарий от anonymous

И так и так можно.

Как минимум forward требует агрумент шаблона, который ты пропустил

annulen ★★★★★
()
Ответ на: комментарий от annulen

Там нет универсальной ссылки. Универсальная ссылка - это когда template<type name T> void foo(T&& tvalue) В результате под шаблон подходит и вариант, когда T=Bar и тогда функция принимает р-валуе ссылку и вариант, когда T=Bar& и тогда после коллапсирования ссылок функция станет принимать л-валуе ссылку. Из за необходимости реализации через шаблон и получаются все перечисленные тобой проблемы. А проведённый вариант - это не универсальная ссылка, а просто перегруженный конструктор.

anonymous
()
Ответ на: комментарий от anonymous

Там нет универсальной ссылки.

Про нее есть в ветке StackOverflow, на которую ссылается ТС. На этой странице дествительно еще не было универсальных ссылок (если на это кто-то ответит, что их вообще не существует, я не возражаю)

annulen ★★★★★
()
Ответ на: комментарий от annulen

Если универсальная ссылка, это && с шаблоном, то я не то имел ввиду, а вот это:

One possible solution (the one adopted by the C++ standard library) is to provide two overloads of add(), one taking an lvalue reference and one taking an rvalue reference:

void add(T const& val) { _impl.push_back(val); }
void add(T&& val) { _impl.push_back(std::move(val)); }

UVV ★★★★★
() автор топика

Второй вариант не имеет смысла, ибо ты делаешь копию а из неё зачем-то пытаешься перемещать. Наверное, ты имел в виду MyClassCtor(DataType&& value) : mValue(std::move(value)) - это move-constructor (ещё желательно добавить noexcept). А использовать move или copy constructor это не вопрос «лучше», а вопрос чего ты хочешь сделать.

slovazap ★★★★★
()
Ответ на: комментарий от UVV

Почему? Типа потому, что массиву ты не можешь сделать move?

Да, также как double и int, для них move не имеет никакого смысла. Вот для std::string имеет.

slovazap ★★★★★
()
Ответ на: комментарий от slovazap

MyClassCtor(DataType&& value) : mValue(std::move(value)) - это move-constructor

С каких щей?? move constructor - это MyClassCtor(MyClassCtor&& value)

UVV ★★★★★
() автор топика
Ответ на: комментарий от annulen

На этой странице дествительно еще не было универсальных ссылок

Я понял о чём ты.. Сейчас читаю Meyers'а, чтобы вникнуть, что это =)

UVV ★★★★★
() автор топика
Ответ на: комментарий от UVV

Я имел в виду перемещающий конструктор в широком смысле.

slovazap ★★★★★
()
Ответ на: комментарий от invy

Тоже вариант, кстати

UVV ★★★★★
() автор топика

Второй всегда лучше для тех объектов, где std::move быстрый, а не полное копирование. Например,

vector<int> f() { return vector<int>(1000000); }
MyClassCtor(f()); // 1 вариант сделает два копирования, если RVO не сработало, и одно копирование, если RVO сработало. 2 вариант не будет делать копирований вообще.
auto val = f();
MyClassCtor(val); // В обоих случаях по 1 копированию
MyClassCtor(std::move(val)); // В первом случае 1 копирование, во втором случае 0 копирований

Но если копирование происходит не всегда, либо нужна не копия, а слегка изменённая копия, то всегда нужно использовать первый вариант.

vzzo ★★★
()
Ответ на: комментарий от anonymous

Второе не universal reference, а rvalue reference. Там не нужен forward, а нужен move. И оно не будет работать для lvalue.

Kuzy ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.