Когда я вижу этот вебинар CPP Con 2017, Федор Пикус говорит: «Это должна быть прямая инициализация».
Это связь на вебинар.
В чем разница между этими методами инициализации? (и, следовательно, почему это должна быть «прямая» инициализация? почему «косвенная» инициализация «НЕ»?)
// C++17 Compiler
#include <atomic>
class Example
{
std::atomic<bool> m_b1 = false; // 1-h
std::atomic<bool> m_b2{ false }; // 2-h
static void example2()
{
std::atomic<bool> b1 = false; // 1-f
std::atomic<bool> b3{ false }; // 2-f
std::atomic<bool> b2(false); // 3-f
// Do something
}
};
@ user17732522 Я исправлен.
std::atomic
нельзя копировать или перемещать.
До C++17 инициализация копированием std::atomic<int> x = 0;
сначала конструировала временный std::atomic<int>
из 0
, а затем напрямую инициализировала x
из этого временного объекта. Без конструктора перемещения или копирования это потерпит неудачу, и поэтому строка не скомпилируется.
std::atomic<int> x(0);
, однако, является прямой инициализацией и просто создаст x
с аргументом 0
конструктору.
Так как в C++17 нет временного объекта, и x
будет напрямую инициализирован вызовом конструктора с 0
в качестве аргумента в любом случае, поэтому нет проблем с тем, что std::atomic
является неподвижным. В этом смысле слайд устарел.
Несмотря на то, что в этом случае поведение для инициализации копированием и прямой инициализации одинаково, в целом между ними все еще есть различия. В частности, прямая инициализация выбирает конструктор для прямой инициализации переменной путем разрешения перегрузки, в то время как инициализация копированием пытается найти неявную последовательность преобразования (возможно, с помощью конструктора преобразования или функции преобразования с другими правилами разрешения перегрузки). Кроме того, инициализация копированием, в отличие от прямой инициализации, не учитывает конструкторы, помеченные explicit
.
Что касается фрагмента кода в вопросе. 1-h
и 1-f
— это инициализация копирования, как указано выше. 3-f
— это прямая инициализация, как указано выше. 2-h
и 2-f
— это прямая инициализация списка, которая в некоторых случаях ведет себя иначе, чем обе другие, но здесь она имеет тот же эффект, что и прямая инициализация со скобками.
Объяснение всех различий между формами инициализации в целом заняло бы некоторое время. Это одна из самых сложных частей C++.
Я всегда думал, что выражение T x = 0;
всегда будет пытаться вызвать конструктор T(int)
независимо от класса
Итак, начиная с С++ 17, все методы «Прямые» и одинаковые?
@Amit Нет, первый метод по-прежнему является инициализацией копирования, а второй - прямой инициализацией. Просто изменился смысл того, что делает копия-инициализация. Эти два метода по-прежнему различаются по нескольким причинам.
@MatG См. тимсонг-cpp.github.io/cppwp/n3337/dcl.init#16.6.2, но временное можно опустить. Он вообще не рассматривает конструкторы, вместо этого он пробует определяемые пользователем последовательности преобразования.
@Amit: Его ответ делает объясняет разницу. В версиях до C++17 создавался временный файл, из которого можно было копировать/перемещать. В пост-С++ 17 этого больше не происходит. Изменилось поведение выражения, а не то, является ли это выражение прямой или копирующей инициализацией. То есть вещь под названием "инициализация копирования" больше не требует "копии" при определенных условиях.
@Amit Я думаю, что упомянул различия, которые здесь имеют значение. Перечисление всех различий между двумя формами инициализации, вероятно, займет некоторое время. Я думаю, наиболее важным из них является то, что инициализация копирования не учитывает конструкторы, отмеченные explicit
.
@Amit Возможно, у stackoverflow.com/questions/1051379/… есть дополнительная информация об общем случае.
@HolyBlackCat, в вебинаре есть ссылка на конкретную временную метку. Это простой пример: thread-1 Read; thread-2 Напишите сценарий, в котором atomic<bool> приходит на помощь вместо простого bool,