programing tip

기본 생성자와 소멸자에서 "= default"는 "{}"과 어떻게 다릅니 까?

itbloger 2020. 6. 12. 21:39
반응형

기본 생성자와 소멸자에서 "= default"는 "{}"과 어떻게 다릅니 까?


나는 원래 이것을 소멸자에 대한 질문으로 만 게시했지만 이제 기본 생성자를 고려하고 있습니다. 원래 질문은 다음과 같습니다.

클래스에 가상의 소멸자를 제공하고 싶지만 컴파일러가 생성하는 것과 동일한 소멸자를 제공하려면 =default다음을 사용할 수 있습니다 .

class Widget {
public:
   virtual ~Widget() = default;
};

그러나 빈 정의를 사용하여 타이핑을 줄이면 동일한 효과를 얻을 수있는 것 같습니다.

class Widget {
public:
   virtual ~Widget() {}
};

이 두 정의가 다르게 행동하는 방법이 있습니까?

이 질문에 대한 답변을 기반으로 기본 생성자의 상황이 비슷해 보입니다. 소멸자에 대해 " =default"와 " {}"의 의미에 거의 차이가 없다는 것을 감안할 때 기본 생성자에 대한 이러한 옵션 사이에 의미에 거의 차이가 없습니까? 즉, 해당 유형의 객체가 생성되고 파괴되는 유형을 생성한다고 가정하면 왜 말하고 싶습니까?

Widget() = default;

대신에

Widget() {}

?

원래 게시물이 일부 SO 규칙을 위반 한 후이 질문을 확장하면 죄송합니다. 기본 생성자에 대해 거의 동일한 질문을 게시하면 바람직하지 않은 옵션으로 생각났습니다.


이것은 소멸자와 생성자에 대해 요청할 때 완전히 다른 질문입니다.

만약 당신의 소멸자가 그렇다면 하워드가 지적한 것처럼virtual 그 차이는 무시할 만하다 . 그러나 소멸자가 가상아닌 경우 완전히 다른 이야기입니다. 생성자도 마찬가지입니다.

= default특수 멤버 함수 (기본 생성자, 복사 / 이동 생성자 / 할당, 소멸자 등)에 구문을 사용 한다는 것은 단순히하는 것과 매우 다른 의미 {}입니다. 후자의 경우, 기능은 "사용자 제공"이됩니다. 그리고 그것은 모든 것을 바꿉니다.

이것은 C ++ 11의 정의에 의한 간단한 클래스입니다.

struct Trivial
{
  int foo;
};

기본 생성을 시도하면 컴파일러에서 기본 생성자를 자동으로 생성합니다. 복사 / 이동 및 파괴도 마찬가지입니다. 사용자가 이러한 멤버 함수를 제공하지 않았으므로 C ++ 11 사양에서는이를 "사소한"클래스로 간주합니다. 따라서 memcpy처럼 내용을 초기화하는 등의 작업을 수행하는 것이 합법적입니다.

이:

struct NotTrivial
{
  int foo;

  NotTrivial() {}
};

이름에서 알 수 있듯이 이것은 더 이상 사소한 것이 아닙니다. 사용자가 제공하는 기본 생성자가 있습니다. 비어 있는지는 중요하지 않습니다. C ++ 11의 규칙에 관한 한, 이것은 사소한 유형이 될 수 없습니다.

이:

struct Trivial2
{
  int foo;

  Trivial2() = default;
};

이름에서 알 수 있듯이 이것은 사소한 유형입니다. 왜? 컴파일러에게 기본 생성자를 자동으로 생성하도록 지시했기 때문입니다. 따라서 생성자는 "사용자 제공"이 아닙니다. 따라서이 유형에는 사용자가 제공 한 기본 생성자가 없으므로 유형이 사소한 것으로 계산됩니다.

= default구문은 같은 기능의 생성을 방지 멤버 함수를 추가 복사 생성자 / 지정, 같은 일을 주로있다. 그러나 컴파일러에서 특수 동작을 트리거하기 때문에 기본 생성자 / 소멸자에서도 유용합니다.


둘 다 사소하지 않습니다.

베이스와 멤버의 noexcept 사양에 따라 둘 다 동일한 noexcept 사양을 갖습니다.

The only difference I'm detecting so far is that if Widget contains a base or member with an inaccessible or deleted destructor:

struct A
{
private:
    ~A();
};

class Widget {
    A a_;
public:
#if 1
   virtual ~Widget() = default;
#else
   virtual ~Widget() {}
#endif
};

Then the =default solution will compile, but Widget won't be a destructible type. I.e. if you try to destruct a Widget, you'll get a compile-time error. But if you don't, you've got a working program.

Otoh, if you supply the user-provided destructor, then things won't compile whether or not you destruct a Widget:

test.cpp:8:7: error: field of type 'A' has private destructor
    A a_;
      ^
test.cpp:4:5: note: declared private here
    ~A();
    ^
1 error generated.

The important difference between

class B {
    public:
    B(){}
    int i;
    int j;
};

and

class B {
    public:
    B() = default;
    int i;
    int j;
};

is that default constructor defined with B() = default; is considered not-user defined. This means that in case of value-initialization as in

B* pb = new B();  // use of () triggers value-initialization

special kind of initialization that doesn't use a constructor at all will take place and for built-in types this will result in zero-initialization. In case of B(){} this won't take place. The C++ Standard n3337 § 8.5/7 says

To value-initialize an object of type T means:

— if T is a (possibly cv-qualified) class type (Clause 9) with a user-provided constructor (12.1), then the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);

— if T is a (possibly cv-qualified) non-union class type without a user-provided constructor, then the object is zero-initialized and, if T’s implicitly-declared default constructor is non-trivial, that constructor is called.

— if T is an array type, then each element is value-initialized; — otherwise, the object is zero-initialized.

For example:

#include <iostream>

class A {
    public:
    A(){}
    int i;
    int j;
};

class B {
    public:
    B() = default;
    int i;
    int j;
};

int main()
{
    for( int i = 0; i < 100; ++i) {
        A* pa = new A();
        B* pb = new B();
        std::cout << pa->i << "," << pa->j << std::endl;
        std::cout << pb->i << "," << pb->j << std::endl;
        delete pa;
        delete pb;
    }
  return 0;
}

possible result:

0,0
0,0
145084416,0
0,0
145084432,0
0,0
145084416,0
//...

http://ideone.com/k8mBrd

참고URL : https://stackoverflow.com/questions/13576055/how-is-default-different-from-for-default-constructor-and-destructor

반응형