Подтвердить что ты не робот

Каковы плюсы и минусы каждого способа инициализации выражения?

Это вдохновлено сообщением Андреем Александреску.

Что такое pro и con для инициализации выражения следующими способами? Когда я должен отдать предпочтение другому?

auto v = expr;
T v = expr;
auto v(expr);
T v(expr);
auto v { expr }; 
T v {expr};
4b9b3361

Ответ 1

auto v = expr;
auto v(expr);

Если в вашем коде либо вы не знаете тип expr и хотите остаться родовым, либо в своем коде, то абсолютно ясно, какой тип expr имеет (определение прямо в строке выше и т.д.), так что auto не добавит путаницы.

Форма инициализации, parens или нет, не имеет значения (имеет отношение только к языковым юристам, поскольку есть тонкие различия). Используйте то, с чем вам комфортнее.


T v = expr;
T v(expr);

Если в вашем коде не ясно, что expr (определение слишком далеко друг от друга и т.д.), или если вы не знаете тип expr, но хотите, чтобы v был типа T. Используйте первую форму, если вы хотите продолжать работать с "видом стоимости", который имеет "expr" (т.е. Если expr - строка, а T - строковый тип). Если вы создаете совершенно новый вид значения (т.е. Widget и expr - цвет виджета), используйте вторую форму.


auto v { expr }; 

Никогда не используйте это в текущем С++ (и, вероятно, в течение ближайших нескольких лет). Он объявит v как std::initializer_list<TypeOfExpr>. Если вы этого хотите, используйте тип напрямую и запишите его. Это слишком тонко (и есть предложения для более-С++ 14, чтобы изменить этот факт, поэтому есть надежда, что вы можете написать это на С++ 17 или что-то в этом роде).


T v {expr};

Если вы хотите защитить себя от сужения конверсий (т.е. от 1000 до char случайно), или если вы хотите инициализировать класс, у которого есть конструктор списка инициализаторов, или если у вас есть совокупность члена ( s) которого вы хотите инициализировать, используйте эту форму. Кроме того, вы можете использовать следующее, если вы имеете дело с конструктором списка инициализаторов, агрегированным или простым неклассовым типом

T v = { expr };

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

T v(expr);

Тем не менее, есть люди, которые предпочитают использовать для этого форму брекетов. Мне нравится точно знать, что делает мой код, поэтому, когда я хочу вызвать конструктор и не хочу случайным образом выполнять вызов конструктора компоновки или списка инициализации вместо этого, я использую parens вместо привязок.  

Ответ 2

auto v = expr; T v = expr; отлично, но в автоматической версии может быть трудно понять тип expr.

Например, в auto x = snafuscate();, каков тип x??

При наличии двусмысленности лучше явно указать тип правой стороны как: auto x = Gadget { snafuscate() };

...

auto v(expr); и T v(expr); - плохая идея, потому что допустимый expr также можно понимать как указатель на функцию.

Этот код не компилируется:

int main()
{
    int x(int());
    return x + 3;
}

prog.cpp:4:11: error: invalid conversion from ‘int (*)(int (*)())’ to ‘int’ [-fpermissive]
return x + 3;
         ^

...

auto v { expr }; почти всегда неверен, потому что тип v становится initializer_list вместо T.

См. рекомендации по использованию auto: http://herbsutter.com/2013/08/12/gotw-94-solution-aaa-style-almost-always-auto/

Ответ 3

Помимо случаев, когда значение отличается (например, vector<int> v(12) не дает вам вектор со значением 12 в нем), компилятор должен дать вам то же самое для всех вышеперечисленных, и это действительно просто личное предпочтение, которое диктует, что "лучше".

auto полезен, когда тип трудно печатать, и тип ясен из контекста. Но auto x = 12; трудно сказать, подписана ли она или нет, например, [я не знаю правил, вероятно, подписанных].

Ответ 4

Я думаю, не нужно использовать auto как

auto x = 12332; // or
auto z = 0xffff; //

Поскольку,

auto x = 12332; // type is  'int'
auto x2 = 0xffff // type is 'int'
auto y = 0xffffffff; // 8 fs,  type is unsigned int
auto z = 0xfffffffff;// 9 fs,  type is long long
auto t = 0xffffffffffffffff; // 16 fs, type is unsigned long long.

Но вы можете использовать

auto size = array.size();

Ответ 5

Это довольно сложный вопрос.

Есть две разные проблемы.

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

auto it = vec.begin();

или если тип очевидный из инициализатора:

auto pfoo = new Foo(x,y,z);

или если вам не нужна читаемость.

Во-вторых, какой тип инициализации использовать. Существует прямая инициализация, инициализация копирования и инициализация списка, а поведение инициализации сильно зависит от типа адресата. Различия между ними описаны в разделе 8.5 стандарта С++. Также инициализация появляется в большем количестве мест, чем просто простые объявления. Интериализация происходит при передаче параметров, возвратных значениях, подвыражениях, условиях оператора, границах массива и многих других местах. Это действительно то, что вам нужно понять, детали и краткое резюме не собираются сокращать его.