web-dev-qa-db-ja.com

C ++、コンストラクターを直接呼び出すことができますか?

オブジェクトのメモリが既にある場合、newを使用せずに明示的にコンストラクタを呼び出すことはできますか?

class Object1{
    char *str;
public:
    Object1(char*str1){
        str=strdup(str1);
        puts("ctor");
        puts(str);
    }
    ~Object1(){
        puts("dtor");
        puts(str);
        free(str);
    }
};

Object1 ooo[2] = {
     Object1("I'm the first object"), Object1("I'm the 2nd")
};

do_smth_useful(ooo);
ooo[0].~Object1(); // call destructor
ooo[0].Object1("I'm the 3rd object in place of first"); // ???? - reuse memory
50
osgx

並べ替え。 placement new を使用して、既に割り当てられているメモリを使用してコンストラクターを実行できます。

 #include <new>

 Object1 ooo[2] = {Object1("I'm the first object"), Object1("I'm the 2nd")};
 do_smth_useful(ooo);
 ooo[0].~Object1(); // call destructor

 new (&ooo[0]) Object1("I'm the 3rd object in place of first");

したがって、newキーワードを引き続き使用していますが、メモリの割り当ては行われません。

76
unwind

新しいプレースメントを探していると思います。 C++ FAQ Lite には、これを行う方法の概要があります。このエントリからいくつかの重要な落とし穴があります。

  1. あなたは#include <new>配置の新しい構文を使用します。
  2. メモリバッファは、作成するオブジェクトに合わせて適切に調整する必要があります。
  3. デストラクタを手動で呼び出すのはあなたの仕事です。
15

建設と破壊の両方で、それをどのように行うことができるかについていくつかのコードを紹介しましょう

#include <new>

// Let's create some memory where we will construct the object.
MyObject* obj = (MyObject*)malloc(sizeof(MyObject));

// Let's construct the object using the placement new
new(obj) MyObject();

// Let's destruct it now
obj->~MyObject();

// Let's release the memory we used before
free(obj);
obj = 0;

上記の要約が物事を明確にすることを願っています。

15
Cthutu

文字通り、いや、「新しい」キーワードなしではできません。実際にメモリを割り当てずに「new」キーワードを使用してコンストラクターを呼び出す方法については、配置に関するすべての回答を参照してください。

5
Ben Voigt

はい、独自の割り当てられたバッファを取得したら、新しい配置を使用します。ブライアンボンディは、関連する質問でここで良い反応を示しています。

「新しいプレースメント」の用途は何ですか?

2
itsmatt

デストラクタを呼び出すことはできますが、メモリは再生されず、関数呼び出しと同等になります。デストラクタの下で2つのことを行うことを覚えておく必要があります。仕様に基づいてオブジェクトを破棄し、メモリを再利用します。とにかくスタックに割り当てられたオブジェクトに対してdtorが呼び出されるため、2回呼び出すと、未定義の動作が発生する可能性があります。

1
vehomzzz

はい、新しい配置を使用します-上記のように、オブジェクトをコピーすることを意味する場合でも、ストレージを管理するための2番目のファクトリクラスを持つことを検討するかもしれません。 memcpy()は、一般に小さなオブジェクトには安価です。

1
Martin Beckett

次のテンプレートを使用できます

template <typename T, typename... Args>
inline void InitClass(T &t, Args... args)
{
    t.~T();
    new (&t) T(args...);
}

使用法:

struct A
{
   A() {}
   A(int i) : a(i) {}
   int a;
} my_value;

InitClass(my_value);
InitClass(my_value, 5);
0
user11258054