placement newにおける、コンストラクタとデストラクタの呼び出し
解決済
回答 1
投稿
- 評価
- クリップ 0
- VIEW 6,890
placement newにおいて、コンストラクタとデストラクタを呼ぶ回数に疑問があります。
以下のコードで、base.~CBase()を明示的に呼ぶことで、コンストラクタとデストラクタを呼ぶ回数を合わせています。
base.~CBase()がない場合、コンストラクタは2回呼ばれますが、デストラクタは1回しか呼ばれません。
(そもそも、デストラクタで後処理を行う前に、その領域に対してplacement newを呼ぶことが好ましくない)
placement newで配置されたオブジェクトのデストラクタは、明示的に呼ばない限り、呼ばれません。
そのため、main関数を抜けて呼ばれるデストラクタは、placement newによって、すでに書き換えられたCBase base(3)が呼ぶデストラクタだと思います。
placement newで領域を書き換えているため、main関数を抜けて呼ばれるデストラクタが表示するメンバの値は、5です。
しかし、意図としては、new(&base) CBase(5)がデストラクタを呼ぶことを期待しているため、何か違和感を感じます。
参考サイト: ロベールのC++教室 - 第49章 破壊と創造 -
#include <iostream>
#include <cstdio>
class CBase {
public:
CBase() = delete;
CBase(int data) : m_data(data) {
std::cout << "CBase::CBase(int data): " << m_data << std::endl;
}
virtual ~CBase() {
std::cout << "CBase::~CBase(): " << m_data << std::endl;
}
static void* operator new(std::size_t size, void* poolPointer) throw(){
std::printf("CBase::operator placement new\n");
return poolPointer;
}
static void operator delete(void* objectPointer, void* poolPointer) throw() {
std::printf("CBase::operator placement delete\n");
}
public:
int m_data;
};
int main() {
CBase base(3);
base.~CBase();
new(&base) CBase(5);
}
また、以下のコードは、後処理を行うために、new(&base) CBase(5)の戻り値を使用して、明示的にデストラクタとplacement deleteを呼んでいます。
この場合、コンストラクタは2回呼ばれ、デストラクタは3回呼ばれます。
しかも、placement deleteが呼ばれた後に、デストラクタが呼ばれるため、違和感を感じます。
int main() {
CBase base(3);
base.~CBase();
CBase* placementBase = new(&base) CBase(5);
placementBase->~CBase();
CBase::operator delete(placementBase, &base);
}
そもそも、ローカル変数のオブジェクトに対してplacement newを使用することが、非常に奇妙なことだと思いますが、それは前提としてください。
以上、宜しくお願い致します。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
0
こんにちは。
通常new/deleteは、メモリの獲得/解放とオブジェクトの構築/解除をセットで行います。
new=メモリの獲得+オブジェクトの構築、delete=オブジェクトの解除+メモリの解放ですね。
このセットを崩すと有用なケースが有るのだと思います。メモリの獲得/解放はmalloc/free等でできますので、オブジェクトの構築と解放だけを呼ぶ方法を作ったのでしょう。
それがプレイスメントnewとデストラクタの直接呼び出しと思います。
コンストラクタの直接呼び出しを許さなかったのは、コンストラクタにメモリ・ポインタを追加する必要があり、全てのコンストラクタを2セット用意することになるので採用しなかったのだと思います。
意図としては、new(&base) CBase(5)がデストラクタを呼ぶことを期待しているため、何か違和感を感じます。
プレイスメントnewやデストラクタの直接呼び出しは、いつも行うメモリ獲得/解放とオブジェクトの構築/解除のセットを崩すので、違和感を感じるのではないでしょうか? デストラクタの直接呼び出しを行った時点でその違和感は許容すべきことのように感じます。
この場合、コンストラクタは2回呼ばれ、デストラクタは3回呼ばれます。
しかも、placement deleteが呼ばれた後に、デストラクタが呼ばれるため、違和感を感じます。
CBase base(3);
のスコープを外れた時に、これに対応するデストラクタを呼ぶコードをコンパイラは作ります。例外処理対応等も考慮したスタックの巻き戻しの仕組みも準備している筈です。
base.~CBase();
のコードは、if文で呼んだり呼ばなかったりすることができます。それぞれに対応して上記のデストラクタ呼び出しを有効にしたり無効にしたりするのは、C++言語の主義に反するように感じます。(デストラクト済フラグは持ってないですから。)
ですので、私は現仕様は素直な印象を受けています。使うかどうかは別として。
プレイスメントnewを使うとスタック上のオブジェクトに対して、遅延コンストラクトが可能になるので何か有用な使い方もありそうな気もします。遅延コンストラクト用のクラス・テンプレートを作れば可読性も悲惨なことにはならないで済むかも? でも、多くのケースでstd::unique_ptr<>を使えば十分な気がします。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.21%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2016/02/21 18:33 編集
やはり、もともと奇妙なことをしているから、につきますか。