2012-01-18 4 views
10

Я в настоящее время чтения в «Язык программирования C++: Special Edition» Бьярне Страуструп и на странице 133 говорится следующее:Предложенное увеличение скорости при определении строки со значением сразу, вместо того, задерживая

Для определяемые пользователем, откладывая определение переменной до , доступный подходящий инициализатор также может привести к повышению производительности . Например:

string s; /* .... */ s = "The best is the enemy of the good."; 

может легко быть гораздо медленнее, чем

string s = "Voltaire"; 

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

Зачем это делать потенциал увеличение производительности?

Действительно ли это относится к пользовательским типам (или даже к типам STL), или это также относится к int, float и т. Д.?

+0

Кроме ответов ниже, это может помочь: http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.22 – dsign

ответ

9

Я бы сказал, что это в основном о типах с нетривиальными конструкторами по умолчанию, по крайней мере, в отношении производительности.

Разница между этими двумя подходами заключается в следующем:

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

Конечно, очень сложно сказать априори, насколько велика разница в производительности.

+0

Разница в производительности отличается для пользовательских типов. практически нет для типов POD. –

7
  1. Это занимает время, чтобы выполнить конструктор по умолчанию. Переопределяя то, что он инициализировал строку в последующем Оператор вызываемого присваивания также требует времени.

  2. Выполнение, возможно, никогда не достигнет назначения, когда функция (из-за оператора return или исключения) оставлена ​​между вызовами конструктора по умолчанию и оператором присваивания. В этом случае объект был по умолчанию инициализирован без необходимости.

  3. Реализации может привести к нерациональному производительности, чтобы убедиться деструктор объекта называется если исключение. Если объект инициализируется в последующей области, которая никогда не была достигнута, это также не требуется.

+1

Я думаю, что проблема сферы является самой важной вещью здесь, и все остальные ответы уклоняются от нее. Что не очевидно из Stroustrup, так это то, что в последнем случае вы можете вообще не использовать переменную. –

1

Потому что:

string s; /* .... */ s = "The best is the enemy of the good.";  

Предполагает две операции: Строительство и присвоение

Хотя:

string s = "Voltaire"; 

Предполагает только строительство.

Это эквивалентно выбору Member Initializer lists over Assignment in Constructor body.

-1

Класс имеет три способа инициализации строки:

string s;   // Default constructor 
string s = "..."; // Default constructor followed by operator assignment 
string s("..."); // Constructor with parameters passed in 

Строка класс должен выделить память. Лучше выделить его, как только он знает, сколько памяти ему нужно.

+2

Второй случай - это инициализация кода и никогда не использует конструктор по умолчанию или оператор присваивания. Это технически построение временного преобразования через ctor, а затем копирование конструкции 's', но избыточная копия обычно удаляется, что делает ее эквивалентной прямой инициализации (случай 3). –

0

Это хороший вопрос. Вы правы, это происходит только со сложными типами. То есть классы и структуры, std :: string - такой объект. Реальная проблема здесь связана с конструктором.

При создании объекта, т.е.

std::string s; 

конструктор Это называется, он, вероятно, выделяет некоторую память, делает какой-либо другой переменной инициализации получает сам готов к использованию. Фактически, в этот момент кода можно было бы выполнить большой объем кода.

Позже вы делаете:

s = "hello world!"; 

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

Это фактически сводится к одной операции, если вы установите значение, если переменная определена, то есть:

std::string s = "Hello world"; 

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

std::string s("Hello world"); 

Я надеюсь, что помог очистить вещи немного.

+1

Собственно, конструктор по умолчанию «строка» хорошей реализации, вероятно, не обязательно выделяет память. Я точно знаю, что gcc 'vector' этого не делает. –

+1

Реальная стоимость, вероятно, связана с тем, что назначение сложнее, чем строительство, поскольку оно должно учитывать удаление и/или повторное использование предыдущего состояния строки. Конструктор знает, что прежнего состояния нет. –

0

Рассмотрите, что происходит в обоих случаях.В первом случае: конструктор

  • по умолчанию называется для «s» оператор
  • присваивание призвал «s»

Во втором случае, сначала рассмотрим, что с копией элизии это эквивалентно string s("Voltaire") , таким образом:

  • строка-си конструктор называется

Логически первый подход требует, чтобы абстрактная машина выполняла больше работы. Действительно ли это переводит на более реальный код, зависит от фактического типа и того, насколько оптимизатор может это сделать. Хотя обратите внимание, что для всех, кроме тривиальных типов пользователей, оптимизатор, возможно, должен предположить, что конструктор по умолчанию имеет побочные эффекты, поэтому не может просто удалить его.

Эта дополнительная стоимость должна применяться только к пользовательским типам, так как стоимость в конструкторе по умолчанию. Для любого примитивного типа, такого как int, или фактически любого с тривиальным конструктором/копией, для конструктора по умолчанию нет затрат - данные просто не будут инициализированы (когда в области функций).

0

Почему это может увеличить потенциальное увеличение?

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

Действительно ли это только с пользовательскими типами (или даже с типами STL), или это также имеет место с int, float и т. Д.?

Это относится только к пользовательским типам; и тогда это зависит от того, что на самом деле выполняют конструкторы и оператор присваивания. Для скалярных типов инициализация по умолчанию ничего не делает, а присваивание делает то же самое, что и инициализация из значения, поэтому обе альтернативы будут эквивалентны.