параметр const против параметра const

Реализация 1:

foo(const Bar x);

Реализация 2:

foo(const Bar & x);

Если объект не будет изменен внутри функции, зачем вам его копировать (реализация 1).

Будет ли это автоматически оптимизировано компилятором?

Резюме: Даже если объект объявлен как const в объявлении функции все еще возможно, что объект будет отредактирован через некоторый другой псевдоним &,

Если вы — человек, пишущий библиотеку, и знаете, что ваши функции этого не делают или что объект достаточно большой, чтобы оправдать стоимость разыменования для каждой операции, тогда
foo(const Bar & x); это путь.

Часть 2:

Будет ли это автоматически оптимизировано компилятором?

Поскольку мы установили, что они не всегда эквивалентны, а условия эквивалентности нетривиальны, компилятору, как правило, будет очень трудно их обеспечить, поэтому почти наверняка нет

7

Решение

ты спрашиваешь,

«Если объект не будет изменен внутри функции, зачем вам его копировать (реализация 1)».

ну, есть некоторые странные ситуации, когда объект, переданный по ссылке, может быть изменен другим кодом, например

namespace g { int x = 666; }

void bar( int ) { g::x = 0; }

int foo( int const& a ) { assert( a != 0 );  bar( a );  return 1000/a; }  // Oops

int main() { foo( g::x ); }

со мной такого никогда не было, с середины 1990-х годов.

так что это наложения спектров это теоретическая проблема для одного аргумента этого типа.

с двумя аргументами одного типа это дает больше реальной возможности. например, оператор присваивания может получить объект, к которому он обращен. когда аргумент передается по значению (как в минимальной форме идиома подкачки), это не проблема, но если нет, то само присваивание как правило, следует избегать.

ты еще спрашиваешь,

«Будет ли это автоматически оптимизировано компилятором?»

нет, не в целом по вышеуказанной причине

компилятор, как правило, не может гарантировать, что не будет псевдонимов для ссылочного аргумента (однако, одно исключение — это то, где машинный код вызова встроен)

однако, с третьей стороны, язык мог возможно поддержали компилятор в этом, например предоставив программисту способ явно принять любую такую ​​оптимизацию, например, сказать «этот код безопасен для оптимизации, заменив проход по значению передачей по ссылке, продолжайте, как вам угодно, компилятор»

3

Другие решения

Действительно, в этих обстоятельствах вы обычно используете метод 2.

Как правило, вы будете использовать метод 1, только если объект крошечный, так что дешевле скопировать его один раз, чем платить за его неоднократный доступ через ссылку (что также влечет за собой затраты). В TC ++ PL, Именно по этой причине Страуструп разрабатывает класс комплексных чисел и передает его по значению.

5

Это может быть оптимизировано в некоторых обстоятельствах, но есть много вещей, которые могут этому помешать. Компилятор не может избежать копирования, если:

  • конструктор или деструктор копирования имеет побочные эффекты, и передаваемый аргумент не является временным.
  • вы берете адрес xили ссылку на него, и передать его в некоторый код, который мог бы сравнить его с адресом оригинала.
  • объект может измениться пока foo работает, например, потому что foo называет некоторые Другой функция, которая меняет это. Я не уверен, что это то, что вы хотите исключить, сказав: «объект не будет изменен в функция «, но если нет, то это в игре.

Вы скопируете его, если что-то из этого имеет значение для вашей программы:

  • если вы хотите побочные эффекты от копирования, возьмите копию
  • если вы хотите, чтобы «ваш» объект имел адрес, отличный от предоставленного пользователем аргумента, сделайте копию
  • если вы не хотите видеть изменения, внесенные в оригинал во время выполнения вашей функции, сделайте копию

Вы также скопируете его, если считаете, что копия будет более эффективной, что, как правило, предполагается для «маленьких» типов, таких как int, Итераторы и предикаты в стандартных алгоритмах также принимаются по значению.

Наконец, если ваш код планирует скопировать объект в любом случае (в том числе путем присвоения существующему объекту), то разумным подходом является сначала взять копию в качестве параметра. Затем переместите / поменяйте местами ваш параметр.

2

Что, если объект был изменен из другого места?

void f(const SomeType& s);
void g(const SomeType s);

int main() {
SomeType s;

std::thread([&](){ /* s is non-const here, and we can modify it */}

// we get a const reference to the object which we see as const,
// but others might not. So they can modify it.
f(s);

// we get a const *copy* of the object,
// so what anyone else might do to the original doesn't matter
g(s);
}

Что если объект является const, но имеет изменяемые члены? Тогда вы все еще можете изменить объект, и поэтому очень важно, есть ли у вас копия или ссылка на оригинал.

Что если объект содержит указатель на другой объект? Если s является const, указатель будет const, но что это указывает на не зависит от константности s, Но создание копии (надеюсь) даст нам глубокую копию, поэтому мы получим наш собственный (const) объект с отдельным (const) указателем, указывающим на отдельный (не const) объект.

В ряде случаев константная копия отличается от константной ссылки.

1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector