30

プラットフォームに依存しないC++コードで、オブジェクトがヒープ上に作成されないようにする方法を知っている人はいますか?つまり、クラス「Foo」の場合、ユーザーがこれを実行できないようにします。

Foo *ptr = new Foo;

そして、これを行うことだけを許可します。

Foo myfooObject;

誰かアイデアはありますか?

乾杯、

4

9 に答える 9

28

ニックの答えは良い出発点ですが、実際にはオーバーロードする必要があるため不完全です:

private:
    void* operator new(size_t);          // standard new
    void* operator new(size_t, void*);   // placement new
    void* operator new[](size_t);        // array new
    void* operator new[](size_t, void*); // placement array new

(適切なコーディングの実践では、delete および delete[] 演算子もオーバーロードする必要があることをお勧めします。私はそうしたいと思いますが、これらの演算子は呼び出されないため、実際には必要ありませ。)

Pauldooは、Foo からの継承は生き残るが、これは Foo での集約には耐えられないということも正しいです。これを防ぐために、テンプレートのメタプログラミング マジックを実行することもできますが、「悪意のあるユーザー」の影響を受けないわけではないため、おそらく複雑にする価値はありません。それがどのように使用されるべきかの文書化と、それが適切に使用されていることを確認するためのコードレビューは、〜100% の唯一の方法です。

于 2008-08-14T16:36:41.233 に答える
10

Fooの新規をオーバーロードして、プライベートにすることができます。これは、Foo内からヒープ上にFooのインスタンスを作成しない限り、コンパイラがうめき声を上げることを意味します。このケースを捕らえるために、Fooの新しいメソッドを書くことができず、リンカーは未定義のシンボルについてうめき声を上げます。

class Foo {
private:
  void* operator new(size_t size);
};

PS。はい、これは簡単に回避できることを私は知っています。私は本当にそれをお勧めしていません-それは悪い考えだと思います-私はただ質問に答えていました!;-)

于 2008-08-14T13:31:05.587 に答える
7

私はそれを確実にそしてポータブルな方法で行う方法を知りません..しかし..

オブジェクトがスタック上にある場合、コンストラクター内で「this」の値が常にスタックポインターに近いことを表明できる場合があります。この場合、オブジェクトがスタック上にある可能性が高くなります。

すべてのプラットフォームが同じ方向にスタックを実装しているわけではないので、アプリがスタックの成長方向を確認し始めたときに1回限りのテストを実行することをお勧めします。

FooClass::FooClass() {
    char dummy;
    ptrdiff_t displacement = &dummy - reinterpret_cast<char*>(this);
    if (displacement > 10000 || displacement < -10000) {
        throw "Not on the stack - maybe..";
    }
}
于 2008-08-14T13:37:17.680 に答える
3

@ニック

これは、Fooから派生またはFooを集約するクラスを作成することで回避できます。私が提案することは(堅牢ではありませんが)、派生クラスと集約クラスでも機能すると思います。

例えば:

struct MyStruct {
    Foo m_foo;
};

MyStruct* p = new MyStruct();

ここでは、Fooの非表示の新しい演算子をバイパスして、ヒープ上に「Foo」のインスタンスを作成しました。

于 2008-08-14T13:39:54.787 に答える
2

デバッグ ヘッダーはオペレーターの新しい署名をオーバーライドできるため、完全な解決策として ... 署名を使用することをお勧めします。

private:
void* operator new(size_t, ...) = delete;
void* operator new[](size_t, ...) = delete;
于 2016-05-26T22:34:20.093 に答える
0

Fooクラス内で「operatornew」と呼ばれる関数を宣言して、通常の形式のnewへのアクセスをブロックすることができます。

これはあなたが望む種類の行動ですか?

于 2008-08-14T13:28:17.243 に答える
0

これをインターフェースとして宣言し、独自のコードからより直接的に実装クラスを制御することができます。

于 2008-08-14T13:41:58.543 に答える
-1

これがコンパイル時の機会を提供するかどうかはわかりませんが、クラスの「new」演算子のオーバーロードを検討しましたか?

于 2008-08-14T13:35:29.087 に答える