Передача значением или ссылкой, конструктору C++, который должен сохранить копию?

Это использовало бы меньше памяти, но вероятно взяло бы дольше

int count = 0;
string line;
TextReader reader = new StreamReader("file.txt");
while ((line = reader.ReadLine()) != null)
{
  count++;
}
reader.Close();
5
задан Kurt Glastetter 4 December 2009 в 17:41
поделиться

8 ответов

В C ++ 98 и C ++ 03 вы должны передать const & bar , а затем скопировать. В C ++ 0x вы должны передать bar , а затем выполнить перемещение (при условии, что bar имеет конструктор перемещения).

#include <utility>

struct foo
{
    bar _b;

    foo(bar b) : _b(std::move(b)) {}
};

Если вы создаете foo с параметром lvalue, копия конструктор будет вызван для создания копии b , и эта копия будет перемещена в _b . Если вы создаете foo с параметром rvalue, будет вызван конструктор перемещения bar для перемещения в b , а затем он снова будет перемещен в _b .

2
ответ дан 18 December 2019 в 11:57
поделиться

При прочих равных условиях я прохожу через const & для достаточно сложных классов и value для POD и простых объектов.

Выделение плюсов и минусов для передачи по константной ссылке вместо традиционного прохода по значению

Положительные:

  • Избегает копирования (большой плюс для объектов с дорогостоящей копией)
  • Доступ только для чтения

Отрицательные:

  • Кто-то может константно исключить константу из ссылки, если они действительно хотел

Что еще более важно с положительными моментами, это то, что вы явно контролируете, когда происходит копирование (в вашем случае при передаче инициализации _b в вашем списке инициализаторов). Думая о негативе ... Согласен, это риск. Я думаю, что почти все хорошие программисты почувствуют себя грязными при использовании const_cast. Более того, вы можете послушно искать const_cast и бросать помидоры в человека, отбрасывающего константу из аргумента. Но эй, никогда не знаешь, и у кого есть время, чтобы наблюдать за кодом, как ястреб :)?

Мое субъективное мнение таково, что в достаточно сложных классах и в средах, где производительность имеет значение, выгода от отказа от конструктора копирования перевешивает риск. Однако для действительно глупых классов и POD я обычно делаю копии данных и передаю их по значению.

5
ответ дан 18 December 2019 в 11:57
поделиться

Стилистически я бы сказал, что передача по ссылке - лучший способ.

Если производительность действительно имеет значение, не гадайте. Измерьте это.

2
ответ дан 18 December 2019 в 11:57
поделиться

Посмотрите этот вопрос .

Используйте const T & arg if sizeof (T)> sizeof (void *) и используйте T arg if sizeof (T) <= sizeof (void *) . Все основные типы должны быть исключением из этого правила

4
ответ дан 18 December 2019 в 11:57
поделиться

Я не проверял, что говорится в стандарте, но, попробовав это эмпирически, могу сказать вам, что GCC не оптимизирует копию, независимо от того, принимает ли конструктор аргумент по значению или по Ссылка на константу.

Однако, если конструктор принимает ссылку на константу, ему удается избежать ненужной копии при создании foo из существующего объекта bar .

Чтобы резюмирую:

Bar b = makeBar();         // No copy, because of RVO
FooByValue f1 = makeBar(); // Copy constructor of Bar called once
FooByRef f2 = makeBar();   // Copy constructor of Bar called once
FooByValue f3(b);          // Copy constructor of Bar called twice
FooByRef f4(b);            // Copy constructor of Bar called only once

Не то, чтобы я был экспертом по компиляторам, но я думаю, имеет смысл, что обычно он не может преобразовать возвращаемое значение в произвольное место (например, поле member объекта foo ) . Вместо этого требуется, чтобы цель находилась наверху стека.

2
ответ дан 18 December 2019 в 11:57
поделиться

Я предполагаю bar имеет обычный конструктор копирования в форме bar (const bar & b)

Возьмите здесь ссылку на const. Затем конструктор bar возьмет эту ссылку и выполнит копирование. Всего копий: 1.

Если вы не указали ссылку, компилятор сделает копию b, передаст копию конструктору foo , который затем передаст ее bar и скопируйте это.

Затем конструктор bar возьмет эту ссылку и выполнит копирование. Всего копий: 1.

Если вы не указали ссылку, компилятор сделает копию b, передаст копию конструктору foo , который затем передаст ее bar и скопируйте это.

Затем конструктор bar возьмет эту ссылку и выполнит копирование. Всего копий: 1.

Если вы не указали ссылку, компилятор сделает копию b, передаст копию конструктору foo , который затем передаст ее bar и скопируйте это.

1
ответ дан 18 December 2019 в 11:57
поделиться

Честно говоря, для этого случая лучший вариант - сделать конструктор встроенным , при условии, что конструктор bar не генерирует. Тогда просто пройдите по ссылке.

Также, как вы подозреваете, ваша статья здесь не применяется.

0
ответ дан 18 December 2019 в 11:57
поделиться

Удерживайте shared_pointer для блокировки в вашем классе и передайте его как таковой. Таким образом, вы никогда не вызовете конструктор копирования :).

-1
ответ дан 18 December 2019 в 11:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: