Почему использование = для инициализации типа примитива в C++?

https://github.com/intuit/karate#ide-support

Я полагаю, что вы найдете нужный плагин на этой странице.

8
задан Deduplicator 29 August 2015 в 11:19
поделиться

9 ответов

Если Вы не доказали, что это имеет значение относительно производительности, я не волновался бы о дополнительной копии с помощью оператора присваивания в примере (std::string foo = "Foo";). Я был бы довольно удивлен, существует ли та копия даже, после того как Вы смотрите на оптимизированный код, я полагаю, что это на самом деле назовет соответствующего параметризованного конструктора.

В ответе на Ваш вопрос, да, я сказал бы, что это - довольно общая конвенция. Классически, люди использовали присвоение для инициализации встроенных типов, и нет неопровержимого довода для изменения традиции. Удобочитаемость и привычка являются совершенно допустимыми причинами этой конвенции, данной, как мало влияния она имеет на окончательном коде.

4
ответ дан 3 November 2019 в 12:57
поделиться

Инициализация переменных с = оператор или с вызовом конструктора является семантически тем же, это - просто вопрос стиля. Я предпочитаю = оператор, так как он читает более естественно.

Используя = оператор обычно не генерирует дополнительную копию - он просто вызывает нормального конструктора. Обратите внимание, однако, что с нетипами примитивов, это только для инициализаций, которые происходят в то же время, что и объявления. Сравните:

std::string strFooA("Foo");  // Calls std::string(const char*) constructor
std::string strFoo = "Foo";  // Calls std::string(const char*) constructor
                             // This is a valid (and standard) compiler optimization.

std::string strFoo;  // Calls std::string() default constructor
strFoo = "Foo";      // Calls std::string::operator = (const char*)

Когда у Вас есть нетривиальные конструкторы по умолчанию, последняя конструкция может быть немного более неэффективной.

Стандарт C++, разделите 8.5, абзац 14 указывает:

Иначе (т.е. для остающихся случаев инициализации копии), временный файл создается. Пользовательские последовательности преобразования, которые могут преобразовать от исходного типа до целевого типа или производного класса этого, перечисляются (13.3.1.4), и лучший выбран через разрешение перегрузки (13.3). Пользовательское преобразование, так выбранное, называют для преобразования выражения инициализатора во временный файл, тип которого является типом, возвращенным вызовом пользовательской функции преобразования со спецификаторами условной цены целевого типа. Если преобразование не может быть сделано или неоднозначно, инициализация плохо формируется. Инициализируемый объект затем инициализируется прямым образом от временного файла согласно правилам выше 87) В определенных случаях, реализации разрешают устранить временный файл путем инициализации объекта непосредственно; см. 12.2.

Часть раздела 12,2 состояний:

Даже когда создания временного объекта избегают, все семантические ограничения нужно уважать, как будто временный объект был создан. [Пример: даже если конструктора копии не вызовут, то все семантические ограничения, такие как доступность (11), должны быть удовлетворены.]

17
ответ дан 3 November 2019 в 12:57
поделиться

Я просто чувствовал потребность в другом глупом сообщении litb.

string str1 = "foo";

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

string str1(string("foo")); 

около проверки, что конструктор преобразования использовал, неявно. На самом деле все неявные преобразования определяются стандартом с точки зрения инициализации копии. Сказано, что неявное преобразование от типа U до типа T допустимо, если

T t = u; // u of type U

допустимо.

В constrast,

string str1("foo");

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

Между прочим, можно отключить игнорирование временных файлов при помощи-fno-elide-constructors:

-fno-elide-constructors
    The C++ standard allows an implementation to omit creating a temporary which 
    is only used to initialize another object of the same type. Specifying this 
    option disables that optimization, and forces G++ to call the copy constructor 
    in all cases.

В Стандарте говорится, что нет практически никакого различия между

T a = u;

и

T a(u);

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


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

T u(v(a));

мог бы смотреть на кого-то как на определение переменной u это инициализируется с помощью временного файла типа v это получает параметр для его вызванного конструктора a. Но на самом деле, то, что компилятор делает с этим, является этим:

T u(v a);

Это создает объявление функции, которое берет аргумент типа v, и с названным параметром a. Таким образом, люди делают

T u = v(a);

снять неоднозначность этого, даже при том, что они, возможно, сделали

T u((v(a)));

также, потому что никогда нет круглых скобок вокруг параметров функции, компилятор считал бы его как определение переменной вместо объявления функции также :)

11
ответ дан 3 November 2019 в 12:57
поделиться

Вы, вероятно, найдете что код такой как

std::string strFoo = "Foo";

постарается не делать дополнительную копию и компиляции к тому же коду (вызов конструктора отдельного аргумента) как тот с круглыми скобками.

С другой стороны, существуют случаи, где нужно использовать круглые скобки, такие как членский список инициализации конструктора.

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

2
ответ дан 3 November 2019 в 12:57
поделиться

Я полагаю, что это - больше привычки, очень немного объектов могли быть инициализированы с помощью =, строка является одним из них. Это - также способ сделать то, что Вы сказали "круглую скобку использования везде (что язык позволяет Вам использовать его)"

0
ответ дан 3 November 2019 в 12:57
поделиться

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

1
ответ дан 3 November 2019 в 12:57
поделиться

Это - проблема стиля. Даже оператор, что "станд.:: представьте в виде строки = "Нечто"; было бы неэффективно, потому что это включит дополнительную копию", не корректно. Эта "дополнительная копия" удалена компилятором.

0
ответ дан 3 November 2019 в 12:57
поделиться

Но затем только смутить Вас еще больше Вы инициализируете примитивы в списке инициализации с помощью объектного синтаксиса.

foo::foo()   
  ,anInt(0)   
  ,aFloat(0.0)   
{   
}   
0
ответ дан 3 November 2019 в 12:57
поделиться

Один аргумент, что можно было сделать для:

станд.:: строковое нечто ("панель");

Это, это сохраняет вещи тем же, даже если количество аргумента изменяется, т.е.:

станд.:: строковое нечто ("панель", 5);

Не работает с '=' знак.

Другая вещь состоит в том, что для многих объектов '=' чувствует себя неестественным, например, скажите, что у Вас есть класс Массива, где аргумент дает длину:

Прибытие массива = 5;

Не чувствует себя хорошо, так как мы не создаем Массив со значением 5, но с длиной 5:

Прибытие массива (5);

чувствует себя более естественным, так как Вы создаете объект с данным параметром, не просто копируя значение.

0
ответ дан 3 November 2019 в 12:57
поделиться
Другие вопросы по тегам:

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