Это использовало бы меньше памяти, но вероятно взяло бы дольше
int count = 0;
string line;
TextReader reader = new StreamReader("file.txt");
while ((line = reader.ReadLine()) != null)
{
count++;
}
reader.Close();
В 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
.
При прочих равных условиях я прохожу через const & для достаточно сложных классов и value для POD и простых объектов.
Выделение плюсов и минусов для передачи по константной ссылке вместо традиционного прохода по значению
Положительные:
Отрицательные:
Что еще более важно с положительными моментами, это то, что вы явно контролируете, когда происходит копирование (в вашем случае при передаче инициализации _b в вашем списке инициализаторов). Думая о негативе ... Согласен, это риск. Я думаю, что почти все хорошие программисты почувствуют себя грязными при использовании const_cast. Более того, вы можете послушно искать const_cast и бросать помидоры в человека, отбрасывающего константу из аргумента. Но эй, никогда не знаешь, и у кого есть время, чтобы наблюдать за кодом, как ястреб :)?
Мое субъективное мнение таково, что в достаточно сложных классах и в средах, где производительность имеет значение, выгода от отказа от конструктора копирования перевешивает риск. Однако для действительно глупых классов и POD я обычно делаю копии данных и передаю их по значению.
Стилистически я бы сказал, что передача по ссылке - лучший способ.
Если производительность действительно имеет значение, не гадайте. Измерьте это.
Посмотрите этот вопрос .
Используйте const T & arg
if sizeof (T)> sizeof (void *)
и используйте T arg
if sizeof (T) <= sizeof (void *)
. Все основные типы должны быть исключением из этого правила
Я не проверял, что говорится в стандарте, но, попробовав это эмпирически, могу сказать вам, что 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 ) . Вместо этого требуется, чтобы цель находилась наверху стека.
Я предполагаю bar
имеет обычный конструктор копирования в форме bar (const bar & b)
Возьмите здесь ссылку на const. Затем конструктор bar
возьмет эту ссылку и выполнит копирование. Всего копий: 1.
Если вы не указали ссылку, компилятор сделает копию b, передаст копию конструктору foo
, который затем передаст ее bar
и скопируйте это.
bar
возьмет эту ссылку и выполнит копирование. Всего копий: 1.
Если вы не указали ссылку, компилятор сделает копию b, передаст копию конструктору foo
, который затем передаст ее bar
и скопируйте это.
bar
возьмет эту ссылку и выполнит копирование. Всего копий: 1.
Если вы не указали ссылку, компилятор сделает копию b, передаст копию конструктору foo
, который затем передаст ее bar
и скопируйте это.
Честно говоря, для этого случая лучший вариант - сделать конструктор встроенным
, при условии, что конструктор bar
не генерирует. Тогда просто пройдите по ссылке.
Также, как вы подозреваете, ваша статья здесь не применяется.
Удерживайте shared_pointer для блокировки в вашем классе и передайте его как таковой. Таким образом, вы никогда не вызовете конструктор копирования :).