ページ 11

placement newの再配置について

Posted: 2009年9月24日(木) 21:02
by array
C++ についての質問です。
指定したメモリアドレスに領域を確保でき、失敗した際には単純にNULLを返すという事なので
placement newを使って、双方リストを作ろうかと考えています。

本題ですが、「placement new」を使用する際、同じアドレスを指定してインスタンス化を行っても
良いのでしょうか。

実際に実行してみると、とくにエラーになることも無く、上書きされる形でインスタンス化できています。
下記が、用途を簡略化してみたプログラムです。
#include <iostoream>
#include <new>

int spase[5];

int main() {
    int *p;

    // 配置領域を指定する
    p = new( &spase[0] ) int;

    *p = 100;

    std::cout << *p << std::endl;

    // 再度同じ領域を指定する
    p = new( &spase[0] ) int;

    *p = 50;

    std::cout << *p << std::endl;

    return 0;
}

Re:placement newの再配置について

Posted: 2009年9月24日(木) 23:59
by Justy

>失敗した際には単純にNULLを返すという

 それは new(std::nothrow) のことでないですか?
 placement newは定したアドレスが返ってくるので、明示的に NULLを指定しない限り
NULLは戻ってきません。



>同じアドレスを指定してインスタンス化を行っても良いのでしょうか。

 大丈夫です。
 ただ、2回目以降でその領域に前にあったオブジェクトが
デストラクタを持っているなら、それを実行しておかないとマズイです。

Re:placement newの再配置について

Posted: 2009年9月25日(金) 00:33
by array
いつも有難うございます

> それは new(std::nothrow) のことでないですか?

勉強不足でした。こうすることでも、NULLが返ってくるんですね。
(この場合でも例外処理を入れたほうが良いのか気になりましたが時間を見つけて調査します。)
私が一番勉強に用いたサイトでは、operator newは、NULLが返ってくると書いてあったので
placement newも同じ動作だろうと思っていました^^;
参考URL:http://www.geocities.jp/ky_webid/cpp/language/036.html


>> 同じアドレスを指定してインスタンス化を行っても良いのでしょうか。

> 大丈夫です。
> ただ、2回目以降でその領域に前にあったオブジェクトが
> デストラクタを持っているなら、それを実行しておかないとマズイです。

よかったです。とりあえずは今考えている方向でプログラムを組んで行こうと思います。

Re:placement newの再配置について

Posted: 2009年9月25日(金) 00:50
by YuO
解決とはなっているのですが,ちょっと気になったので……。

> 勉強不足でした。こうすることでも、NULLが返ってくるんですね。

new演算子が失敗したときに確実にNULLが返る<new>にあるoperator newの形式は,
>void* operator new(std::size_t size, const std::nothrow_t&) throw();
以外にあり得ません。

>void* operator new(std::size_t size, void* ptr) throw();
は確かにptrを返すとされていますが (IS 18.4.1.3 Placement forms / Paragraph.2),
new (NULL) fooはoperator newの後のオブジェクトの構築処理で空ポインタへの参照が発生し,未定義の振る舞いとなる可能性があります。
# new(NULL) foo();とか致命的。

なので,記憶域の割り付けに失敗した場合にNULLを返したいのであれば,const std::nothrow_t&を引数に取る物を使うべきです。

なお,operator newが例外を発生させないからと行って,new演算子が例外を発生させないとは限りません。
new演算子は,
・operator newによる例外
・構築されるインスタンスのコンストラクタによる例外
の2種類の異なる理由による例外を発生させます。
たとえconst std::nothrow_t&を引数に取るバージョンでも後者は発生しうるので,例外に対する対策は必要になります。
# だからvoid operator delete (void * ptr, const std::nothrow_t&) throw();が定義されている。

Re:placement newの再配置について

Posted: 2009年9月25日(金) 01:52
by array
YuOさん、有難うございます。

注意してもらった事項を頭にいれてプログラミングしていきたいと思います。
もしかしたら、また同じような内容で悩む事があるかもしれないので、その時はまた
よろしくお願いします