読者です 読者をやめる 読者になる 読者になる

nothrowなdelete

C++

C++のnew演算子は、失敗時にデフォルトでstd::balloc例外を投げますが、std::nothrowを指定することにより、失敗時にヌルが返ってくるようにできます:

#include <new>

int main()
{
    int* p = new(std::nothrow) int[3]; // 失敗時にヌルが返る
    if (p == nullptr) { ... }
    delete[] p;
}

このnothrow版のnew演算子も、ほかの演算子と同様に置き換え可能になっています。そして、置き換え可能な演算子には、なぜかnothrow版のdeleteもあります:

void operator delete(void* ptr, const std::nothrow_t&) noexcept;
void operator delete[](void* ptr, const std::nothrow_t&) noexcept;

これは一体何者なのでしょうか。通常の「delete p」もしくは「delete[ ] p」という呼び出しでは、これらの演算子は呼び出されず、throw可能なオーバーロードが呼び出されます。これを明示的に呼び出すには、以下のように「operator delete[ ](p, std::nothrow)」とする必要があります。

#include <iostream>
#include <new>
#include <cstdlib>

void* operator new(std::size_t size, const std::nothrow_t&) noexcept
{
    void* ptr = std::malloc(size);
    std::cout << "new:" << size << " " << ptr << std::endl;
    return ptr;
}

void operator delete[](void* ptr, const std::nothrow_t&) noexcept
{
    std::cout << "free:" << ptr << std::endl;
    std::free(ptr);
}

int main()
{
    int* p = new(std::nothrow) int[3];
    operator delete[](p, std::nothrow);
}
new:12 0x327d30
free:0x327d30

nothrow版のdeleteが呼び出されました。このdelete演算子は、標準ではthrowを許可するdelete演算子を呼び出すだけなので、動作に違いはありません。なので、この演算子は「ユーザーが置き換えて使用する場合に使い分けてもいい」ということを許可するためにあるようです。

https://twitter.com/kikairoya/statuses/266086241555054592
http://twitter.com/melponn/status/266086208680099841
http://twitter.com/melponn/status/266087356942143488
嘘書きました・・・。