2011-04-05 1 views
1

標準は5.3.4[expr.new]/7新しい(size、value)Type [0]によって返されるポインタは正当なものであり、配列を作成するために使用できますか?

で言う直接新しい宣言内の式の値がゼロである場合、割り当て機能はない要素を持つ配列を割り当てるために呼び出されます。

ゼロサイズの要求が未定義であるとして3.7.3.1[basic.stc.dynamic.allocation]/2

にポインタをデリファレンスの効果が返されます。

しかし、割り当て関数がユーザ定義で、有効なポインタを返したとわかっていれば、逆参照するための未定義の動作ですか?標準では、ユーザーコードの未定義の動作を強制できますか?

私が尋ねる理由は、非デフォルト構成可能型のオブジェクトの動的配列を初期化するもう一つの無意味な試みです。 delete[]の明白な欠如に加えて、それにはどのような問題があり、それは[0]でしか呼び出せないのでしょうか? aligned_storageも正しく使用しましたか?

#include <type_traits> 
#include <stdexcept> 
#include <memory> 
#include <iostream> 

struct T { 
    int val; 
    T() = delete; 
    T(int i) : val(i) {} 
    void* operator new[](std::size_t, std::size_t cnt, const T& t) 
    { 
     typedef std::aligned_storage<sizeof(t), 
        std::alignment_of<T>::value>::type buf; 
     T* ptr = reinterpret_cast<T*>(new buf[cnt]); 
     std::uninitialized_fill_n(ptr, cnt, t); 
     return ptr; 
    } 
}; 

int main() 
{ 
    T* a = new(100, T(7)) T[0]; // using zero is legal per 5.3.4/7 

    std::cout << "a[0] = " << a[0].val << '\n' // but is this legal? 
       << "a[1] = " << a[1].val << '\n' 
       << "a[98] = " << a[98].val << '\n' 
       << "a[99] = " << a[99].val << '\n'; 
    delete[] a; // free the 100 aligned_storages 
} 

テスト実行:と予想通りhttp://ideone.com/iBW0z

もキャストがあるときreinterpret_castの結果の使用の唯一の非未定義の動作があるMSVC++ 2010 EE

+0

:-) ...今の良い探しています"なぜ' std :: vector'で十分ではないのですか?それはまさにこれを可能にします。 – ildjarn

+0

@ildjarn:それだけで十分です。私は言語の境界を探っています。 – Cubbi

+0

十分に公正な: - ] – ildjarn

答えて

3

あなたのコードに刺激性のロジックに問題があります:

新しい表現:

T* a = new(100, T(7)) T[0]; 

はTの削除デフォルトコンストラクタ[expr.new]/17を呼び出します。 ;-(

std::vector<T>は確かに私が尋ねる理由は、デフォルト以外の、構成可能型のオブジェクトの動的配列を初期化するためのさらに別の無意味な試みである。* *」

+0

私は、コンストラクタがアクセス可能であることを望んでいます。私がC++を凌駕しようとするたびに、それは私を圧倒します。 – Cubbi

+2

新しい式を使用する代わりに、演算子newを直接呼び出すことができます。これは本質的にベクターがするものです。しかし、ベクターはすでにそれを行っているので、動機付けのユースケースが何であるか分かりません。あなたがそれを要求しない限り、vectorはデフォルトで構築可能である必要はありません。 –

+0

動機は '新しい(...)T [0]'を正当化しようとする試みであり、その動機は好奇心であった。 – Cubbi

1

でコンパイルし、実行しますその元のタイプに戻って、他にすべてがうまくいてもあなたはすでにUBを持っています。

これが本当に必要な場合は、十分大きなブロックの連続メモリを割り当て、次にnewの配置Tをそのメモリに割り当てる機能を作ってみませんか?

+0

私はポインタをインクリメントしてvoidにキャストしているだけですが、 'aligned_storage'の配列を新しくするのではなく、' T * 'を返す' get_temporary_buffer'を呼び出す方が良いでしょうか?それを別の関数にするということは、単にベクトルを実装していることを意味します。 – Cubbi

関連する問題