3

C++ 11 (c++98/03 標準にも当てはまります) 標準 (以下を参照) から、既に定義されているため、新しい関数の演算子をグローバル空間に配置することはできません。

18.6.1.3 配置フォーム [new.delete.placement]

これらの関数は予約済みです。C++ プログラムは、標準 C++ ライブラリ (17.6.4) のバージョンを置き換える関数を定義できません。(3.7.4) の規定は、演算子 new および演算子削除のこれらの予約配置形式には適用されません。

これは、以下のスニペットのポイント 2> によって証明されており、予想どおりにコンパイル エラーが発生します。

しかし、クラスレベルで新しい配置をオーバーライドすることはできます。これは正常に機能します。以下のスニペットのポイント (2) を参照してください。何故ですか?標準に従って、(2) も防止しようとするべきではありません。

以下のスニペットを参照してください。

class Test
{
public:
    Test(int i):m_i(i) { cout << "Test::Test()" << endl; }
    ~Test() { cout << "Test::~Test()" << endl; }

    //(1)class level override placement new
    void* operator new (std::size_t size) throw (std::bad_alloc) {
        cout << "My class level new" << endl;
        return malloc(size);
    }

    //(2)class level override placement new
    void* operator new (std::size_t size, void* ptr) throw() {
        cout << "My class level non-throwing placement new" << endl;
        return ptr;
    }
private:
    int m_i;

};

//<1>global replacement for operator new - single object form
void* operator new (std::size_t size) throw (std::bad_alloc) {
    cout << "My global new" << endl;
    return malloc(size);
}


//<2>global replacement for operator new - replcement  form
//NB. This is a attempt that definitely fails according to c++ stadnard:
//does get compile error: error: redefinition of 'void* operator new(std::size_t, void*)'
/*
void* operator new (std::size_t size, void* ptr) throw() {
    cout << "My global non-throwing placement new" << endl;
    return ptr;
}
*/

int main() {
    Test* p = new Test(1);
    delete p;

    cout << "" << endl;
    void* mem = operator new(sizeof(Test));
    Test* p2 = new(mem) Test(1);
    p2->~Test();
    operator delete (mem);

    return 0;
}

以下は、期待どおりの出力です。

My class level new
My global new
Test::Test()
Test::~Test()

My global new
My class level non-throwing placement new
Test::Test()
Test::~Test()

================================================== ================================ 私の質問に対するさらなる説明:

18.6.1.3 配置形式これらの関数は予約されています。C++ プログラムは、標準C++ ライブラリ (17.6.4)のバージョンを置き換える関数を定義できません 。(3.7.4) の条項は、これらの予約済み配置フォームには適用されません。

operator new および operator delete の。

これは、私のスニペットのポイント <2> で予想されるコンパイル エラーを説明しているので、これは問題ありません。

しかし、クラスの明確化内のポイント (2) でクラス レベルのプレースメント フォームを置き換えることができるのはなぜですか?

4

1 に答える 1

2

§18.6.1.3 には、次の形式がリストされています。

void* operator new(std::size_t size, void* ptr) noexcept;
void* operator new[](std::size_t size, void* ptr) noexcept;
void operator delete(void* ptr, void*) noexcept;
void operator delete[](void* ptr, void*) noexcept;

「C++ プログラムは、標準 C++ ライブラリのバージョンを置き換える関数を定義してはならない」という規則は、どの名前空間にもないこれら 4 つの関数宣言にのみ適用されます。クラスまたは名前空間で独自のバージョンを作成しても問題ありません。

実際、独自のプレースメントを新しく提供する必要がある場合があります。クラスで法線を宣言すると、標準ライブラリによって提供される配置 new が非表示になります。この構文operator newを使用する場合は、独自の配置 new をクラスに追加する必要があります。new (ptr) T(...)

これは、呼び出し::new (ptr) T(...)が標準配置 new のように動作することが保証されていることを保証するだけです。::(プレフィックスに注意してください。)

于 2012-10-17T15:06:59.993 に答える