コンテンツにスキップ

最終更新:2026-10-12

C++ と Rust のデストラクタ比較

Rustではmem::forgetはオブジェクトのデストラクタを防ぎ、クリーンアップ作業をスキップして、リソースの解放を他の仕組みに任せるために使われます。

例えば:

let file = File::open("foo.txt").unwrap();
mem::forget(file);

ではC++ではどうやってデストラクタを防ぐのでしょうか?すなわち、デストラクタをスキップするには?

本節では3つの方法を示します。完全なコード例も星球に掲載しています。

1. placement new

placement newを使うと、オブジェクトの構築と破棄を手動で管理できます。オブジェクトのデストラクタを手動で呼び出さなければ、オブジェクトのデストラクタをスキップでき、mem::forgetと同様の効果を実現できます。

例えば:

alignas(Foo) std::byte storage[sizeof(Foo)];  // 分配对齐的原始内存块
Foo* pfoo = new (storage) Foo();  // 在这块内存上构造Foo对象

上のコードでは、placement newがオブジェクトpfooを生成していますが、デストラクタを呼ばないことで、オブジェクトのクリーンアップ処理をスキップできます。

2. スマートポインタのカスタムデリータを使う

同様の機能を実現するもうひとつの方法は、スマートポインタのデリータをカスタマイズして、オブジェクトが破棄されるのを防ぐことです。何もしないデリータを定義することで、デストラクタの呼び出しを避けられます。

std::unique_ptr<Foo, NoOpDeleter> pfoo(new Foo(), NoOpDeleter{});

カスタムデリータNoOpDeleterを使うことで、std::unique_ptrがスコープを抜けるときにデストラクタを呼び出すのを防ぎ、mem::forgetと同様の効果を実現できます。

3.union

unionの方法はなかなか不思議です。原理を皆さんはご存じでしょうか?コメント欄で一緒に議論しましょう~

template <class T>
union Wrapper {
  T value;
  ~Wrapper() {}
};

struct Foo {
  ~Foo() { std::cout << "dtor foo\n"; }
};

Wrapper<Foo> f; 
// f.value.~Foo);  必须手动调用

関連トピック

コメント