Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > [C++11] =default. зачем ?


Автор: borisbn 11.1.2013, 09:39
Здравствуйте.
Не могу понять, для чего в новом стандарте ввели конструкцию =default; для конструкторов и деструкторов.
Несколько раз перечитал http://stackoverflow.com/questions/13576055/how-is-default-different-from-for-default-constructor-and-destructor, но всё равно ничего не понял.
Подскажите, пожалуйста, чем отличается это
Код
struct A {
};

от этого
Код
struct A {
    A() {}
};

и от этого
Код
struct A {
    A() = default;
};

И тот же вопрос про деструкторы (как про обычные, так и виртуальные).
Спасибо.
P.S. Чем отличается это
Код
struct A {
};

от этого
Код
struct A {
    virtual ~A() {}
};

объяснять не нужно ))

Добавлено через 2 минуты и 2 секунды
Если не сложно, то объясните ещё про =delete;
Чем это
Код
struct A {
private:
    A() {}
};

отличается от этого
Код
struct A {
private:
    A() = delete;
};

Автор: bsa 11.1.2013, 10:48
borisbn, подумай, что ты будешь делать, если тебе нужно заменить конструктор копирования, а дефолтный конструктор ты хочешь оставить умолчальным (например, чтобы использовать конструкции вида Class x = {1,2,3,4};)
С delete все аналогично. Во втором случае даже "друзья" и "члены" не смогут вызвать дефолтный конструктор. Да и компилятор в любом случае ругнется правильней.

Автор: borisbn 11.1.2013, 11:03
Цитата(bsa @  11.1.2013,  10:48 Найти цитируемый пост)
Во втором случае даже "друзья" и "члены" не смогут вызвать дефолтный конструктор

ясно. принято.

Цитата(bsa @  11.1.2013,  10:48 Найти цитируемый пост)
если тебе нужно заменить конструктор копирования, а дефолтный конструктор ты хочешь оставить умолчальным 

а тут не очень. ну... меняю я конструктор копирования, умолчальный при этом пропадает. Это ясно. А чем это
Код
struct A {
    A( int, int, int, int ) { ... }
    A() = default;
};

отличается от этого
Код
struct A {
    A( int, int, int, int ) { ... }
    A() {}
};

?

Добавлено через 47 секунд
и что с деструкторами ?

Автор: mes 11.1.2013, 12:52
Цитата

A trivial class or struct is defined as one that:
Has a trivial default constructor. This may use the default constructor syntax (SomeConstructor() = default;).
Has trivial copy and move constructors, which may use the default syntax.
Has trivial copy and move assignment operators, which may use the default syntax.
Has a trivial destructor, which must not be virtual.
Constructors are trivial only if there are no virtual member functions of the class and no virtual base classes. Copy/move operations also require that all of the non-static data members be trivial.
A type that is standard-layout means that it orders and packs its members in a way that is compatible with C. A class or struct is standard-layout, by definition, provided:
It has no virtual functions
It has no virtual base classes
All its non-static data members have the same access control (public, private, protected)
All its non-static data members, including any in its base classes, are in the same one class in the hierarchy
The above rules also apply to all the base classes and to all non-static data members in the class hierarchy
It has no base classes of the same type as the first defined non-static data member
A class/struct/union is considered POD if it is trivial, standard-layout, and all of its non-static data members and base classes are PODs.
By separating these concepts, it becomes possible to give up one without losing the other. A class with complex move and copy constructors may not be trivial, but it could be standard-layout and thus interop with C. Similarly, a class with public and private non-static data members would not be standard-layout, but it would be trivial and thus memcpy-able.

Автор: borisbn 11.1.2013, 13:27
всё равно не понятно... если бы компилятор не давал бы передавать non-trivial объекты в функции типа memcpy, то я бы понял. А так... ну какая мне по большому счёту разница, trivial или нет мой класс ?
Если я сделаю так
Код
std::string s1, s2;
memcpy( & s1, & s2, sizeof( s1 ) );

компилятор меня не остановит... к сожалению
И опять же, чем A(){} от A() = default; отличается ?

Автор: bsa 11.1.2013, 14:12
Цитата(borisbn @  11.1.2013,  14:27 Найти цитируемый пост)
И опять же, чем A(){} от A() = default; отличается ? 

я же написал! в случае с дефолтным конструктором можно использовать инициализацию всех полей класса в месте определения. А в случае кастомного - нельзя.
Как только у тебя дефолтный конструктор становится нетривиальным (A(){} - это нетривиальный конструктор), то с твоего класса тут же снимается маркировка POD со всеми вытекающими. Таким образом, без возможности объявить конструктор по умолчанию дефолтным, без потери POD ты не можешь сделать другие конструкторы, которые тебе, возможно, очень бы пригодились.

Автор: borisbn 11.1.2013, 14:39
Цитата(bsa @  11.1.2013,  14:12 Найти цитируемый пост)
в случае с дефолтным конструктором можно использовать инициализацию всех полей класса в месте определения. А в случае кастомного - нельзя.

ок. Это ясно. Но всё равно остаются вопросы, вернее просьба - не могли бы Вы привести пример (не просто Class x = { 1, 2, 3, 4 };, а рабочий), в котором без =default; что-то не компилируется, а с ним - работает.
У меня такое
Код
struct A {
    int x;
    int y;
//    A( int a_x ) : x( a_x ), y( 0 ) {}   // <-- так тоже не работает. даже без конструктора копирования
    A( const A & other ) : x( other.x ), y( other.y ) {}
    A() = default;
};

int main() {
   A a = { 33, 42 };
   cout << a.x << " " << a.y << endl;
   return 0;
}

не работает...
И чем тогда отсутствие кастомного конструктора отличается от A() = default; ?
Сорри за тупые вопросы, но теория у меня всегда хромала... мне бы примерчик ))

Автор: bsa 11.1.2013, 18:02
Цитата(borisbn @  11.1.2013,  15:39 Найти цитируемый пост)
не работает...
ну значит или компилятор не поддерживает, или я ошибся с примером (скорее всего).

Автор: borisbn 11.1.2013, 18:09
Цитата(bsa @  11.1.2013,  18:02 Найти цитируемый пост)
ну значит или компилятор не поддерживает

проверял на LWS
Код
cout << "GCC version = " << __VERSION__ << endl;

Цитата
GCC version = 4.7.2

http://liveworkspace.org/code/2k3V9U$2

Автор: volatile 12.1.2013, 00:03
Цитата(borisbn @  11.1.2013,  14:39 Найти цитируемый пост)
чем тогда отсутствие кастомного конструктора отличается от A() = default; ?

Когда определен какой-то конструктор, не важно какой, скажем:
Код

struct A {
    A(int) {...}
};

то невозможно создать объект по умолчанию.
А а; // <== не скомпилируецца.

Чтобы скомпилировалось, раньше нужно было создавать пустой конструктор:
A() {}
Сейчас достаточно написать
A ()  = default;

Разница правда не столь существенна, но все-же так чищще, и определенней.
Кроме того 
Цитата

Declaring a function as defaulted after its first declaration can provide efficient execution and concise definition while enabling a stable binary interface to an evolving code base.

имхо.


Автор: volatile 12.1.2013, 01:03
Ну и кроме, того, в тех случаях когда можно писать а можно и не писать дефолный конструктор, 
явное указание говорит о том что мы не забыли его написать, а что именно это мы и хотели получить.
(стилевое улучшение как бэ..)

Что интересно, пробовал его поместить в приватную часть. но он молча компилируецца как публичный.
(в принципе компилятору неплохо бы ругаться в этом случае...)

Автор: borisbn 12.1.2013, 14:27
Цитата(volatile @  12.1.2013,  00:03 Найти цитируемый пост)
Чтобы скомпилировалось, раньше нужно было создавать пустой конструктор:
A() {}
Сейчас достаточно написать
A ()  = default;

т.е. всё-таки нет разницы ?

Цитата(volatile @  12.1.2013,  01:03 Найти цитируемый пост)
стилевое улучшение как бэ..

не верится, что в стандарт ввели эту фичу исключительно для стиля... про const тоже можно было бы сказать "для стиля", однако все понимают, что это не так...
в общем, понимания пока нет.
А с деструктором - тем более...
ждёмс...

Автор: Dem_max 12.1.2013, 16:53
Наверное пока еще никто не понимает зачем., а чтение мануалов результата не дает. 

Автор: volatile 12.1.2013, 18:03
Цитата(borisbn @  12.1.2013,  14:27 Найти цитируемый пост)
не верится, что в стандарт ввели эту фичу исключительно для стиля... 

borisbn, стиль - не много не то слово. Точнее - большая самодокумментируемость, и определенность.
Страус, как бэ открытым текстом говорит, что это излишество. 
Цитата

Being explicit about the default is redundant. However comments about copy operations and (worse) a user explicitly defining copy operations meant to give the default behavior are not uncommon. Leaving it to the compiler to implement the default behavior is simpler, less error-prone, and often leads to better object code. 


Кроме того эта фича полезна для копи-мув конструкторов.
Если определить кастомный копи конструктор, то дефолтный move контруктор не будет автоматически создан.
И если он нужен, то придецца его писать. А это не просто пустой оператор {}. Там придецца напрячься.
=default решает эту проблему.

http://www.stroustrup.com/C++11FAQ.html#default

Автор: borisbn 13.1.2013, 16:19
Цитата(volatile @  12.1.2013,  18:03 Найти цитируемый пост)
Если определить кастомный копи конструктор, то дефолтный move контруктор не будет автоматически создан.
И если он нужен, то придецца его писать. А это не просто пустой оператор {}. Там придецца напрячься.
=default решает эту проблему.

ага... что-то проясняецца ))

Цитата(borisbn @  11.1.2013,  09:39 Найти цитируемый пост)
И тот же вопрос про деструкторы (как про обычные, так и виртуальные).

Цитата(borisbn @  11.1.2013,  11:03 Найти цитируемый пост)
и что с деструкторами ? 

Цитата(borisbn @  12.1.2013,  14:27 Найти цитируемый пост)
А с деструктором - тем более...
ждёмс... 

?

Автор: volatile 13.1.2013, 23:27
Тэкс.., насчет деструкторов.
Цитата(borisbn @  11.1.2013,  09:39 Найти цитируемый пост)
для чего в новом стандарте ввели конструкцию =default; для конструкторов и деструкторов.

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

Последних правда не так много, это : конструктор по умолчанию, копи/мув конструктор, копи/мув оператор=, и деструктор. (если ничо не забыл).

Согласитесь, было бы не логично, вводя данную фичу для всех функций, делать какие-то особые исключения для деструкторов.

В общем, в том случае если вы не считаете что это повышает стройность (логическую завершенность, self-descriptivenes, и т.д) можете считать, что деструкторы попали "под раздачу".

Все что я написал, это IMHO на текущий момент.
я могу ошибацца.

PS: Щас то я попривык уже, но раньше, мне жутко не нравилось, что компилятор, без моего ведома, вставляет какие-то дефолтные функции. 
Да еще вставляет не всегда, а по каким-то не совсем очевыдным условиям... 
Идеально было бы вовсе запретить ему вставлять что либо, без специального указания.
Но, увы, этого уже не исправить.
А с добавлением move операций (мув-конструктора, и мув-оператора=), ситуация приобрела бы в этом плане, вообще паталогический характер.
Сложные логические условия, в каких случаях генерируюцца тот или иной конструктор/оператор, нужно знать, и держать в голове.
Фичи (=default,=delete), разруливают эту ситуацию, да еще и сглаживают прошлые недостатки.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)