LINUX.ORG.RU

способы инициализации классов

 


0

2
struct Test
{
    Test(int a, int b)
    : a_(a), b_(b) {}

    int a_;
    int b_;
};

Test ch1 = Test(1, 2);  // #1
Test ch3 = Test({1, 2}); // #2
Test ch4 = Test{1, 2};   // #3

Test ch5(1, 2);  // #4
Test ch6({1, 2});  // #5
Test ch7{1, 2};   // #6

Test ch8 = {1, 2}; // #7

Ребят, просветите, есть ли какая-то разница между инициализацией с разными скобками? Почему это всё работает?

Насколько я понимаю, у 4-5-6 не происходит копирование временного объекта.

(в контексте С++14)



Последнее исправление: lvmuser (всего исправлений: 3)

В #7 тоже не происходит.

anonymous
()

А в #5 происходит.

anonymous
()

Почему это всё работает?

Такой язык.

anonymous
()

https://habr.com/ru/company/jugru/blog/469465/

https://en.cppreference.com/w/cpp/language/copy_elision

Ребят, просветите, есть ли какая-то разница между инициализацией с разными скобками?

Есть.

Test test1(0.0, 4.2);  // ok
Test test2{ 0.0, 4.2 }; // error: narrowing conversion of ‘1.0e+0’ from ‘double’ to ‘int’

Варианты с разнообразным вкладыванием фигурных скобок будут отрабатывать по-разному в зависимости от объявленных конструкторов.

Кроме того, при наличии конструктора из std::initializer_list Test{1, 2} в данном примере будет вызовет именно его.

Siborgium ★★★★★
()
Последнее исправление: Siborgium (всего исправлений: 3)

у 4-5-6 не происходит копирование временного объекта.

так нигде не происходит копирования здесь

xperious ★★
()
Последнее исправление: xperious (всего исправлений: 1)

А документацию открыть слабо? Что ты от нас хочешь, чтобы мы тебе с выражением её прочитали?

slovazap ★★★★★
()
Ответ на: комментарий от anonymous

Удали конструкторы копирования и перемещения. Результат тебя удивит.

То что в части приведённых случаев язык требует их наличия вовсе не означает что они будут дёрнуты (при включенных оптимизациях). На copy elision rules ссылку уже давали. Смотрите на disasm если есть сомнения - это надёжней всего.

bugfixer ★★★★★
()
Ответ на: комментарий от bugfixer

То что в части приведённых случаев язык требует их наличия вовсе не означает что они будут дёрнуты

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

anonymous
()
Ответ на: комментарий от anonymous

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

У Саттера в одной из его Exceptional С++ очень неплохо описано что реально происходит и почему (там правда ещё только 98ые плюсы, но всё равно очень познавательно).

А вообще у нас в конторе в подавляющем большинстве случаев #4 (тот который ch5) используется, как самый explicit и не допускающий разночтений.

bugfixer ★★★★★
()
Ответ на: комментарий от lvmuser

https://habr.com/ru/company/jugru/blog/469465/

Автор подводит такой итог:

  1. var = value; // инициализация копированием. Стоит использовать для простых типов

  2. var = {args}; var = {}; // copy-list-initialization

  • для агрегатной инициализации: int nums[] = {1,2,3,4};
  • для прямой иниц. членов класса: MyClass = {1.0f, 222, «abc»};
  • для конструкторов, принимающих std::initializer_list
  1. var {args}; var {}; // direct-list-initialization Для передачи и возврата объектов.
  • для иниц. временных объектов: func(MyClass{1, 2, 3})
  • для инициализации членов класса: MyClass{} - к примеру, если нет конструктора, int-члены класса инициализируются нулями.
  1. obj(args); // для вызова конструкторов. Тут есть нюанс - если написать MyClass test(args); - компилятор примет это за объявление функции. Сработает лишь: MyClass test = MyClass(args);
lvmuser
() автор топика
Ответ на: комментарий от lvmuser

Инициализация в с++ это мемасик и вполне вероятно ты тралишь, но если нет, то погугли гифку. В с++20 уже нет особой разницы между () и {}, и то и другое вызовет какой-то конструктор, либо проинициализирует значение, но это не точно. Если не хочешь тронуться головой, то пиши везде круглые скобки, компилятор сам оптимизирует или выдаст ошибку. Предпочитаемым способом вызова конструктора являются круглые скобки, если ты не хочешь вызывать конструктор, то напиши что-то другое.

Про разницу в инициализации между с++11 и с++14 про который ты спрашивал - это для гурманов, если будут спрашивать - посылай нах*й, тебя тоже стоило бы послать, но ты мне уже как брат.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.