MyClass a1 {a}; // clearer and less error-prone than the other three
MyClass a2 = {a};
MyClass a3 = a;
MyClass a4(a);
Почему?
MyClass a1 {a}; // clearer and less error-prone than the other three
MyClass a2 = {a};
MyClass a3 = a;
MyClass a4(a);
Почему?
В основном копирование и вставка из The C ++ Programming Language 4th Edition Бьярна Страуструпа:
Инициализация списка не позволяет сужать (§iso.8.5.4). То есть:
Пример:
void fun(double val, int val2) {
int x2 = val; // if val == 7.9, x2 becomes 7 (bad)
char c2 = val2; // if val2 == 1025, c2 becomes 1 (bad)
int x3 {val}; // error: possible truncation (good)
char c3 {val2}; // error: possible narrowing (good)
char c4 {24}; // OK: 24 can be represented exactly as a char (good)
char c5 {264}; // error (assuming 8-bit chars): 264 cannot be
// represented as a char (good)
int x4 {2.0}; // error: no double to int value conversion (good)
}
Единственная ситуация, когда = предпочтительнее {}, - это использование ключевого слова auto
для получения типа, определенного инициализатором.
Пример:
auto z1 {99}; // z1 is an int
auto z2 = {99}; // z2 is std::initializer_list<int>
auto z3 = 99; // z3 is an int
Предпочитайте {} инициализацию альтернативным вариантам, если у вас нет веских причин не делать этого.
()
может быть проанализировано как объявление функции. Это сбивает с толку и непоследовательно, что вы можете сказать T t(x,y,z);
, но не T t()
. А иногда, вы уверены x
, вы даже не можете сказать T t(x);
.
- person juanchopanza; 14.08.2013
std::initializer_list
. RedXIII упоминает об этой проблеме (и просто отмахивается от нее), в то время как вы полностью игнорируете ее. A(5,4)
и A{5,4}
могут вызывать совершенно разные функции, и это важно знать. Это может даже привести к звонкам, которые кажутся не интуитивно понятными. Сказать, что вы должны предпочесть {}
по умолчанию, приведет к тому, что люди неправильно поймут, что происходит. Но это не твоя вина. Я лично считаю, что это крайне плохо продуманная функция.
- person user1520427; 02.02.2015
std::initializer_list
конструктора может изменить семантику существующего {}
вызова. Честно говоря, я не понимаю, как вы можете прийти к такому выводу, но, может быть, это просто потому, что я думаю, что для этой части языка нужно было приложить больше усилий. Ну что ж.
- person user1520427; 03.02.2015
std::initializer_list
, является единственной причиной для рассмотрения альтернатив. В всех сценариях предпочтительна {}
инициализация. Дай мне знать, если я чего-то не понимаю.
- person Oleksiy; 03.02.2015
auto var{ 5 }
, и он будет выводиться как int
, но не как std::initializer_list<int>
.
- person Edoardo Dominici; 31.10.2015
auto z3 = {99}; // z3 is an std::initializer_list<int>
.
- person Georg; 11.12.2016
struct X{int i; int j}; X {5};
, который будет компилироваться; но оставьте j неинициализированным
- person UKMonkey; 09.05.2018
T &t{otherT}
, но не T &t{otherT, somethingElse}
, но можете сказать const T& t{otherT}
и const T& t{otherT, somethingElse}
. Однако в первом случае &t == &otherT
, но во втором случае создается временный файл. Инициализация в старом стиле последовательно защищает от этой опасности и просто делает вариант с несколькими аргументами плохо сформированным.
- person Johannes Schaub - litb; 18.11.2018
Уже есть отличные ответы о преимуществах использования инициализации списка, однако мое личное эмпирическое правило - НЕ использовать фигурные скобки, когда это возможно, а вместо этого делать его зависимым от концептуального значения:
По моему опыту, этот набор правил можно применять гораздо более последовательно, чем использование фигурных скобок по умолчанию, но необходимо явно запоминать все исключения, когда они не могут быть использованы или имеют другое значение, чем «нормальный» синтаксис вызова функции с круглыми скобками. (вызывает другую перегрузку).
Это, например, хорошо сочетается со стандартными типами библиотек, такими как std::vector
:
vector<int> a{10,20}; //Curly braces -> fills the vector with the arguments
vector<int> b(10,20); //Parentheses -> uses arguments to parametrize some functionality,
vector<int> c(it1,it2); //like filling the vector with 10 integers or copying a range.
vector<int> d{}; //empty braces -> default constructs vector, which is equivalent
//to a vector that is filled with zero elements
const int &b{}
‹- не пытается создать неинициализированную ссылку, а привязывает ее к временному целочисленному объекту. Второй пример: struct A { const int &b; A():b{} {} };
‹- не пытается создать неинициализированную ссылку (как это сделал бы ()
), а привязывает ее к временному целочисленному объекту, а затем оставляет его висящим. GCC даже с -Wall
не предупреждает для второго примера.
- person Johannes Schaub - litb; 18.11.2018
std::initialize_list
конструктора, но Foo foo{a,b}
в любом случае имеет смысл поместить a and b
в контейнер / структуру данных foo
(в противном случае я бы рекомендовал не использовать {}
abyway), тогда я не могу представить причину, по которой потенциальный будущий std Конструктор :: initializer_list изменит семантику этого вызова. Если такой конструктор означает что-то, кроме вышеупомянутого, это, по-моему, просто плохой дизайн шрифта.
- person MikeMB; 14.09.2020
Существует МНОГО причин использовать инициализацию скобок, но вы должны знать, что конструктор initializer_list<>
предпочтительнее других конструкторов, за исключением конструктора по умолчанию. Это приводит к проблемам с конструкторами и шаблонами, где конструктор типа T
может быть либо списком инициализаторов, либо простым старым ctor.
struct Foo {
Foo() {}
Foo(std::initializer_list<Foo>) {
std::cout << "initializer list" << std::endl;
}
Foo(const Foo&) {
std::cout << "copy ctor" << std::endl;
}
};
int main() {
Foo a;
Foo b(a); // copy ctor
Foo c{a}; // copy ctor (init. list element) + initializer list!!!
}
Предполагая, что вы не сталкиваетесь с такими классами, есть небольшая причина не использовать список инициализаторов.
{ ... }
), если вам не нужна семантика initializer_list
(ну и, возможно, для создания объекта по умолчанию).
- person Xeo; 14.08.2013
std::initializer_list
вообще существует - оно просто добавляет путаницы и путаницы в язык. Что плохого в использовании Foo{{a}}
, если вам нужен конструктор std::initializer_list
? Это кажется намного проще для понимания, чем приоритет std::initializer_list
над всеми другими перегрузками.
- person user1520427; 02.02.2015
Foo{{a}}
следует некоторой логике для меня гораздо больше, чем Foo{a}
, который превращается в приоритет списка инициализаторов (пользователь может подумать, хм ...)
- person Gabriel; 19.04.2015
std::initializer_list<Foo>
конструктора, но он будет добавлен в класс Foo
в какой-то момент для расширения его интерфейса? Потом облажались пользователи класса Foo
.
- person doc; 29.05.2015
Foo c {a}
просто вызывает ctor копирования, начиная с CWG 1467 (по крайней мере, реализовано в clang)
- person Cubbi; 08.02.2016
initializer_list<>
), которая на самом деле не соответствует критериям того, кто считает ее предпочтительной, а затем упоминается один хороший случай, когда она НЕ предпочтительна. Что мне не хватает, что еще ~ 30 человек (по состоянию на 21.04.2016) сочли полезными?
- person dwanderson; 21.04.2016
copy ctor\ncopy ctor
. Разве список инициализаторов не должен выполняться со второго вызова? --std=c++17
. Это изменилось?
- person Daniel Stephens; 30.09.2019
Это безопаснее, если вы не строите с -Wno-сужением, как, скажем, Google в Chromium. Если да, то это МЕНЬШЕ безопасно. Однако без этого флага единственные небезопасные случаи будут исправлены C ++ 20.
Примечание: A) Фигурные скобки безопаснее, потому что они не позволяют сужаться. Б) Фигурные скобки менее безопасны, потому что они могут обходить частные или удаленные конструкторы и неявно вызывать явно отмеченные конструкторы.
Эти две комбинации означают, что они безопаснее, если то, что находится внутри, является примитивными константами, но менее безопасно, если они являются объектами (хотя и исправлено в C ++ 20).
std::map<std::string, std::vector<std::string>>::const_iterator
хотел бы поговорить с вами. - person Xeo   schedule 14.08.2013auto
. Конечно, это мог быть просто забавный укол, который не следует останавливать фактами. ;) - person Xeo   schedule 14.08.2013typedef std::map<std::string, std::vector<std::string>> MyContainer
обычно более чистая альтернатива. Я используюauto
только для типов локальной области видимости. - person doc   schedule 29.05.2015using MyContainer = std::map<std::string, std::vector<std::string>>;
даже лучше (тем более, что вы можете его использовать по шаблону!) - person JAB   schedule 19.02.2016unsigned int n = 7;
vs.auto n = 7U;
- суффикс легко забыть (что на самом деле произошло в первом варианте, намеренно, в демонстрационных целях, однако первый вариант является устойчивым), что приводит кn
плохого типа. Еще хуже:auto n = 7UL;
там, где вы хотите, чтобы n было типаuint64_t
- и BAM, мы не на 64-битном Linux и просто получаем вместо этогоuint32_t
(или, возможно, даже не этот, посколькуuint32_t
может быть определен какunsigned int
в текущей системе, а вы может закончиться, например, несовместимыми указателями). - person Aconcagua   schedule 13.08.2018