2012-04-11 2 views
1

int/double/등의 생성자 의미 체계입니다. 다음과 같습니다 :기본 형식의 생성자 의미를 모방 한 C++ 형식을 만들 수 있습니까?

정확하게 동일한 동작으로 클래스를 정의 할 수 있습니까? 즉, 기본 생성자를 초기화하지 않고 초기화한 모두가있는 것입니까? 저는 이것이 불가능하다고 믿습니다. 그리고 현재는 0으로 호출 될 때만 컴파일되는 생성자를 만들지 만 근본적인 형식을 정확히 모방 할 방법이 없는지 확인하고자합니다.

+3

나는 (당신이 단지 위의 숫자를 모으는 POD에 대해 말하지 않는 한) 꽤 없다고 확신합니다. –

+0

'int b = int();'는 실제로 _value-initialization_이며, 단지 스칼라에 제로 - 초기화의 효과가 있습니다. 그리고 내가 당신의 동기를 정확하게 추측한다면, 당신은 [Boost.Optional] (http://www.boost.org/libs/optional/)을 볼 것을 제안 할 것입니다. – ildjarn

+1

초기화되지 않은 변수를 원한다면 어떤 근거가 있습니까? 유스 케이스를 설명하면 아마도 더 좋은 방법이 될 것입니다. – bta

답변

2

가 더 생성자가 정의되지 않은 경우 :

struct A { int x; }; 

A a; // default-initialized (unintialized) 
A b = A(); // value-initialized 
A c = { 4 }; // four 
+0

네, @ Jerry의 코멘트를보십시오. 그러나 "고전적인"OOD 클래스는 아닙니다. – littleadv

+0

흠. 나는 이것이 효과가 없다고 믿었지만, valgrind는 나에게 어떤 식 으로든 말하지 않는다. 내가 아는 한, A()는 아직 초기화되지 않았습니다. –

+0

이것이 실제로 작동하면 나는 알고 싶어한다. 다른 사람이 이것이 올바른지 알고 있습니까?내 작은 테스트 프로그램은 "초기화 된"및 "값 초기화 된"두 가지 경우 모두에 0을 인쇄하지만 두 경우 모두 0이 우연이라고 생각합니다. Valgrind는 문제의 메모리가 스택 재사용이기 때문에 아마도 아무 것도 말하지 않습니다. –

0

어떤 경우에도 기본 생성자는 호출 할 수 없습니다.

+3

첫 번째 예에서는 생성자가 호출됩니다. 전혀 "초기화되지 않은"것은 아닙니다. – Mat

+0

기본 생성자가 항상 호출됩니다. – littleadv

2

기본 제공 유형과 반대로 클래스 생성자가 이 항상이되므로 불가능합니다.

"초기화되지 않은"개체를 정말로 만들고 싶다면 (왜 초기화되지 않은 변수로 인해 버그가 충분하지 않습니까?) 배치 new으로 트릭을해야합니다.

+0

얼마나 자주 stackoverflow 사람들은 완벽하게 합리적인 질문 충격을받습니다. C++의 디자인 원칙 중 하나는 사용자 정의 유형이 내장 유형에 가능한 한 동일해야하며 이는 언어의 한 가지 구멍입니다. 또한 관련 코드에서 초기화되지 않은 변수에 의해 발생하는 유일한 오류는 valgrind 덕분에 초기화가 0 인 경우를 찾기가 훨씬 어려웠습니다. –

+1

@Geoffrey : "* C++의 디자인 원칙 중 하나는 사용자 정의 유형이 내장 유형에 가능한 한 동일해야한다는 것입니다. *"아니요. 기본 유형과 스칼라는 모두 특별한 의미를 지니고 있습니다. C++ 표준, 특히 _ 초기화와 관련됩니다. – ildjarn

+1

@GeoffreyIrving하지만 C++의 또 다른 원칙은 기본적인 기본 제공 유형이 ** 클래스가 아닌 ** 클래스라는 것입니다. 무언가를 'int'로 'typedef'한다면, 그것은'int'와 똑같이 행동 할 것입니다. 왜 비 클래스 유형과 클래스 유형이 동일하게 동작 할 것이라고 기대합니까? 그리고 나는 그것에 대해 전혀 즐겁지 않습니다. – littleadv

-1
class A { 
public: 
    A() {} 

}; 
A* a = (A*)malloc(sizeof(A)); 

(.! 아이들을 집에서이 작업을 수행하지 않는 모든이 작업을 수행하지 마십시오)

+2

그게 내가 '새로운'트릭 배치를 사용하여 의미했던거야 ... BTW : C++ 코드에서'malloc'을 사용하지 마십시오. 나쁜 나쁜 습관입니다. 당신이 그것을'삭제 '하거나'자유롭게 할'것인지 어떻게 알 수 있을까요? – littleadv

+0

@littleadv, 당신은 그것을 기억해야합니다. :-) 그래서 나는'집에서하지 마라. '라고 썼다. – nothrow

+2

@Yossarian, 적어도 당신의 닉은이 솔루션의 광기와 일치합니다 : D – Griwes

2

"초기화되지 않은 건설은"모순 어법이다.

초기화의 부족은 버그 (전체 개체를 재귀 적으로 생성하지 못함)의 결과로 발생합니다.

C++ 클래스에 생성자가 있으면 호출됩니다. 어떤 이유로 든 호출 할 수없는 경우 해당 상황은 잘못된 것입니다 (예를 들어 생성자와 일치하지 않는 잘못된 생성자 인수가 전달 된 경우).

C++ 클래스에는 기본 유형의 멤버가 포함될 수 있으며 생성자는 해당 멤버를 초기화하지 않을 수 있습니다.

이것은 최적화를 위해 악용 될 수 있습니다. 나중에 발생하는 복잡한 초기화가있는 경우 해당 멤버에 쓰는 오버 헤드를 피할 수 있습니다.

초기화하지 않고 남아있을 수있는 전체 클래스를 만들지 않고이를 수행하는 방법이 될 것입니다.

정말로 원한다면 생성자없이 POD (일반 오래된 데이터 구조)를 만든 다음 몇 가지 추가 기술을 사용하여 초기화를 보장 할 수있는 방법으로 사용할 수 있습니다. 예를 들어, 구조를 추가하거나 기이하게 반복되는 템플릿 패턴을 사용하는 파생 클래스를 만듭니다.

그런 다음 초기화하지 않으려면 POD를 직접 사용할 수 있습니다.

+0

초기화되지 않은 생성자를 만드는 방법을 이미 알고 있습니다. 초기화되지 않은 값과 초기화 된 생성자가 공존 할 수 있는지 여부는 문제입니다. –

1

기본 계약자가 항상 호출됩니다. 할 수있는 "트릭"이 많이 있지만이 동작을 원하는 이유와 사용자 코드를 어떻게 보이게 할 것인지에 따라 다릅니다. 데이터 멤버를 사용하지 않고 호출 할 수있는 특별한 생성자를 정의 할 수 있습니다. 아니면 다양한 일을 할 수 있습니다. 하나의 옵션은 ...

템플릿으로도 재생할 수 있습니다.

struct uninitialized_ctor {}; 

class Foo 
{ 
public: 
    int x; 
    Foo() : x(42) 
    { 
    std::cout << "Foo::Foo\n"; 
    } 
protected: 
    Foo(uninitialized_ctor const &) 
    { 
    std::cout << "Foo::Foo - uninitialized\n"; 
    } 
}; 


struct UninitializedFoo : public Foo 
{ 
    UninitializedFoo() 
    : Foo(uninitialized_ctor()) 
    { 
    // Does not call base class ctor... 
    std::cout << "UninitializedFoo\n"; 
    } 
}; 


int main(int, char *[]) 
{ 
    Foo foo1; 
    UninitializedFoo foo2; 
    Foo * f1 = new Foo(); 
    Foo * f2 = new UninitializedFoo(); 

    std::cout << foo1.x << '\n' << foo2.x << '\n' << f1->x << '\n' << f2->x << '\n'; 
} 

하지만 - 그것은 당신의 진짜 목적이 무엇인지에 따라 달라집니다 ... 어떻게 코드에 영향을 미치기 사용자 ...

0

집계 클래스 유형은 기본적으로 동작을 당신이 좋아 :

struct Foo { int a; int b; }; 

Foo x; // x.a, x.b uninitialized 

Foo * p = new Foo(); // p->x, p->y value-initialized, i.e. zero 

Foo y { 1, 2 }; // brace-initialization does what you think 

Foo z { };  // brace-initialization can also "fake" value-init for automatics 

집계의 경우 default 및 value 초기화가 반복적으로 구성원에게 전파됩니다.

struct Bar 
{ 
    int a; 
    int b; 
    Bar() : a() { } // no b! 
    Bar(int a_, int b_) : a(a_), b(b_) { } 
}; 

Bar x; // x.a is value-, x.b is default-initialized 
0

이 아마도 당신이 이런 식으로 뭔가를 할 수 :

사소한 소멸자가 필요

template<typename T> 
struct uninitialized { 
    static_assert(std::is_trivially_destructible<T>::value,"T must have trivial dtor"); 

    alignas(T) char raw[sizeof(T)]; 

    template<typename... Us> 
    T &initialize(Us &&... us) { 
     return *(new (raw) T(std::forward<Us>(us)...)); 
    } 

    T &get() { return reinterpret_cast<T&>(raw); } 
}; 
때문에 그렇지 않으면 당신 '당신은 또한 초기화되지 않은 멤버 잎이 아닌 집계를 만들 수 있습니다 물론

객체를 적절히 파괴하기 위해 객체가 구축되었는지 여부를 추적해야합니다.