1

int/double/etc のコンストラクタのセマンティクス。それは:

int a; // uninitialized
int b = int(); // zero initialized
int c = int(4); // four

まったく同じ動作のクラスを定義することは可能ですか? つまり、初期化されていないデフォルト コンストラクタと初期化されているデフォルト コンストラクタの両方を持つものですか? 私はこれは不可能だと考えており、現在、0 で呼び出された場合にのみコンパイルするコンストラクターを作成することで回避していますが、基本的な型を正確に模倣する方法がないことを確認したいと考えています。

4

8 に答える 8

2

組み込み型とは対照的に、クラスコンストラクターは常に呼び出されるため、不可能です。

本当に「初期化されていない」オブジェクトを実行したい場合(初期化されていない変数のために十分なバグがないのはなぜですか?)new、おそらく配置でトリックを実行する必要があります。

于 2012-04-11T21:01:33.800 に答える
2

コンストラクターが定義されていない場合:

struct A { int x; };

A a; // default-initialized (unintialized)
A b = A(); // value-initialized
A c = { 4 }; // four
于 2012-04-11T21:05:39.417 に答える
2

「初期化されていない構造」は矛盾しています。

構築時の初期化の欠如は、バグ (オブジェクト全体を再帰的に構築できない) の結果としてのみ発生します。

C++ クラスにコンストラクターがある場合は、それが呼び出されます。なんらかの理由で呼び出すことができない場合、その状況は誤りです (たとえば、コンストラクターと一致しない間違った構築引数が渡されたなど)。

C++ クラスには基本型のメンバーを含めることができ、そのコンストラクターはそれらのメンバーの初期化を無視できます。

これは最適化に悪用される可能性があります。後で発生する複雑な初期化がある場合、それらのメンバーへの書き込みのオーバーヘッドを回避できます。

初期化されていないままにしておくことができるクラス全体を作成しようとするのではなく、それを行う方法です。

本当にそれが必要な場合、それをエミュレートする方法は、コンストラクターなしで POD (plain old datastructure) を作成し、いくつかの追加の手法を使用して、初期化を保証する方法で使用できるようにすることです。たとえば、構造を追加する派生クラスを作成したり、不思議なことに繰り返されるテンプレート パターンを利用したりします。

初期化しない場合は、POD を直接使用できます。

于 2012-04-11T21:14:13.500 に答える
1

デフォルトの請負業者が常に呼び出されます。実行できる「トリック」はたくさんありますが、それは、この動作が必要な理由と、ユーザーコードをどのように見せたいかによって異なります。データメンバーに対して何も行わない特別なコンストラクターを定義して、それを呼び出すことができます。または、さまざまなことを行うことができます...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';
}

しかし-それはあなたの本当の目標が何であるかによって異なります...そしてそれがコードのユーザーにどのように影響するか...

于 2012-04-11T21:25:35.490 に答える
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

アグリゲートの場合、デフォルトおよび値の初期化はメンバーに再帰的に伝播します。

もちろん、メンバーを初期化しないままにする非集計を作成することもできます。

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
于 2012-04-11T21:27:24.873 に答える
0

不可能です。いずれの場合もデフォルトのコンストラクターが呼び出されます。

于 2012-04-11T21:00:42.327 に答える
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); }
};

そうしないと、オブジェクトを適切に破棄するために、オブジェクトが構築されたかどうかを追跡する必要があるためです。

于 2012-04-11T21:32:08.113 に答える
-1
class A { 
public:
    A() {}

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

(子供たち、家でこれをしないでください。これをまったくしないでください!)

于 2012-04-11T21:06:47.147 に答える