2017-07-11 23 views
2

を呼び出さずにオブジェクト配列を作成するカスタムベクトルクラスが必要です。ここでは、テンプレートパラメータを使用してコンパイル時に容量が設定されます。組み込みシステム用のコンストラクタ

これまでメンバー変数としてオブジェクトの配列がありました。

template<class T, size_t SIZE> 
class Vector { 
    ... 
    T data[SIZE]; 
} 

もちろん、ここでの問題は、TがPODでない場合、Tのデフォルトのコンストラクタが呼び出されることです。対応するpush()呼び出し(内部に新しいプレースメントがある)までデータを初期化しないようにする方法はありますか?ただ、

uint8_t data[SIZE * sizeof(T)]; 

はおそらく我々は絶対に動的メモリを使用することはできませんT.のアラインメントを破る使用して、合計コンテナのサイズは、常にコンパイル時に知られている必要があります。コンパイラはまだC++ 11をサポートしていませんので、我々はまた、C++のalignas指定子を使用することはできません:(

+0

好奇心から:「Tのアラインメントを壊す」とはどういう意味ですか?'sizeof(T)'バイトの中にあるものに限定された問題はありませんか?私はこれがどのように問題を引き起こすかを見ていません – user463035818

+1

これまで最高の解決策ではありませんが、オブジェクトを「初期化されていない」、ブール値などで保存されたデフォルトのコンストラクタを作成するだけではできませんか? – Aziuth

+1

新しいプレースメントのユースケースに似ています。 –

答えて

1

あなたが適切に設定され、アライメントを得るために労働組合のトリックと一緒に配置newを使用する必要があるとしている。

// use `std::max_align_t` and `std::aligned_storage` when you have it 
// since don't have access to alignof(), use the presumably max 
// alignment value 
using MaxAlign = long; 

template <typename T, int size> 
class UninitializedArray { 

    union Node { 
     char data[sizeof(T)]; 
     MaxAlign alignment; 
    }; 

    Node aligned_data[size]; 
    bool initialized; 

public: 

    UninitializedArray() : initialized(false) {} 
    void initialize() { 
     for (int i = 0; i < static_cast<int>(size); ++i) { 
      new (&this->aligned_data[i].data) T(); 
     } 
     this->initialized = true; 
    } 
    ~UninitializedArray() { 
     if (this->initialized) { 
      for (int i = 0; i < static_cast<int>(size); ++i) { 
       T* ptr = reinterpret_cast<T*>(&this->aligned_data[i].data); 
       ptr->~T(); 
      } 
     } 
    } 

    T& operator[](int index) { 
     if (!this->initialized) { 
      this->initialize(); 
     } 

     T* ptr = reinterpret_cast<T*>(&this->aligned_data[i].data); 
     return *ptr; 
    } 
}; 
その後、

そして、あなたがこれまでC++ 17の作業を取得した場合、その後、あなたが目を作るためにstd::arraystd::optionalを使用することができ、この

UninitializedArray<Something, 5> arr; 
arr[0].do_something(); 

のようにそれを使用します簡単

std::optional<std::array<T, N>> optional_array; 

// construct the optional, this will construct all your elements 
optional_array.emplace(); 

// then use the value in the optional by "treating" the optional like 
// a pointer 
optional_array->at(0); // returns the 0th object 
1

まず、コンパイラは、アライメントをサポートしている場合、私はすなわちgccの__attribute__(aligned(x))があり、同様の可能性が高いものがある、チェックしますです。あなたは絶対にそのようなサポートなしで初期化されていないデータを整列している必要がある場合

その後、あなたは

// Align must be power of 2 
template<size_t Len, size_t Align> 
class aligned_memory 
{ 
public: 
    aligned_memory() 
     : data((void*)(((std::uintptr_t)mem + Align - 1) & -Align)) {} 
    void* get() const {return data;} 
private: 
    char mem[Len + Align - 1]; 
    void* data; 
}; 

いくつかのスペースを無駄にする必要がありますそして、あなたはそれ

template<typename T, size_t N> 
class Array 
{ 
public: 
    Array() : sz(0) {} 
    void push_back(const T& t) 
    { 
     new ((T*)data.get() + sz++) T(t); 
    } 

private: 
    aligned_memory<N * sizeof(T), /* alignment */> data; 
    size_t sz; 
}; 

Live

で新しい配置を使用したいです

Tのアラインメントは、C++ 11 alignofで見つけることができます。その整列を見つけるために使用できるものはすべてサポートしています。また、印刷されたポインタの値から推測するだけでも十分です。

1

別の方法は、std::vector<>をスタックに割り当てるカスタムアロケータで使用することです。

この方法で、空のベクトルを作成し、必要な領域を確保します。この領域は、アロケータがスタックに割り当てた領域と同じでなければなりません。vector<>::emplace_backを使用してベクトルに値を設定します。要素タイプはコピー不可能ですが、この場合は移動可能でなければなりません。

例えば:アロケータを実装する方法について

#include <vector> 

struct X { 
    X(int, int); 

    // Non-copyable. 
    X(X const&) = delete; 
    X& operator=(X const&) = delete; 

    // But movable. 
    X(X&&); 
    X& operator=(X&&); 
}; 

template<class T, std::size_t N> 
struct MyStackAllocator; // Implement me. 

int main() { 
    std::vector<X, MyStackAllocator<X, 10>> v; 
    v.reserve(10); 
    v.emplace_back(1, 2); 
    v.emplace_back(3, 4); 
} 

情報は、例えば、「C++アロケータ」のためのYouTubeを検索し、広く利用可能です。

関連する問題