How to initialize a sequence of non-movable, non-copyable objects?

Let's say I have a type that is neither movable nor copied:

struct foo { explicit foo( size_t ){} ~foo(){} foo( foo const & ) = delete; foo( foo && ) = delete; foo& operator=( foo const & ) = delete; foo& operator=( foo & ) = delete; }; 

Now, given the number known at compile time (call it N), is there a way I can create a β€œsequence” of them on the stack, each of which is initialized with numbers from 0 to N-1? I would be pleased with the C-style array foo[N] , a std::array< foo, N > or maybe even std::tuple .

I am trying to avoid:

 foo f0( 0 ), f1( 1 ), ... fNminus1( N-1 ); 

when it seems like this is what the compiler should do for me. The best I could come up with was to use boost::optional .

 boost::optional< foo > f[N]; for( size_t i = 0U; i < N; ++i ) f[i] = boost::in_place( i ); 

But it depends on the execution logic, although all the necessary information is available at compile time. Also, I was left with something that behaves like an array of pointers.

+5
c ++ constructor compile-time
source share
3 answers
 // create a type with the proper alignment typedef std::aligned_storage<sizeof(foo), std::alignment_of<foo>::value>::type buffer_type; const int N = 10; // create an array of uninitialized raw data buffer_type storage_buffer[N]; // initialize each foo object with placement new for (size_t i=0; i<N; ++i) new (storage_buffer + i) foo(i); foo * fp = (foo*)(&storage_buffer); // access your foo objects via fp // you must manually call the destructor of each object for (size_t i=0; i<N; ++i) fp[i].~foo(); 

If this seems like a lot of trouble, it is. But you can easily encapsulate this functionality in a class.

+3
source share

Although this is not strictly an array, you can accomplish this with template recursion

 template< typename T, size_t N > struct type_array : public type_array< T, N-1 > { // this is the Nth element T elem; // it is constructed with N type_array() : elem( N ) {} // member function to return the Nth element T & get( size_t n ) { if ( n == N ) { return elem; } else { return type_array< T, N-1 >::get( n ); } } }; // base case when N == 0 template< typename T > struct type_array<T, 0> { T elem; type_array() : elem( 0 ) {} T & get( size_t n ) { return elem; } }; 

Using:

 type_array< foo, 100 > foo_array; // construct 100 foos foo_array.get(1); // foo with n == 1 foo_array.get(2); // foo with n == 2 
+1
source share

Like Benjamin Lindley's answer, but packed in class:

 #include <type_traits> #include <utility> #include <new> template<typename T> class uninitialized { public: constexpr uninitialized() { } ~uninitialized() { get().~T(); } explicit uninitialized(const uninitialized& other) { construct(other); } explicit uninitialized(uninitialized&& other) { construct(std::move(other)); } template<class... Args> explicit uninitialized(Args&&... args) { construct(std::forward<Args>(args)...); } template<class... Args> void construct(Args&&... args) noexcept { static_assert(std::is_nothrow_constructible<T, Args...>::value, "constructor should not throw!"); ::new(getPointer()) T (std::forward<Args>(args)...); } uninitialized& operator = (const T& t) { get() = t; return *this; } uninitialized& operator = (T&& t) { get() = std::move(t); return *this; } T* operator -> () { return getPointer(); } T& operator * () { return get(); } T* operator & () { return getPointer(); } T* getPointer() { return reinterpret_cast<T*>(&data); } T& get() { return *reinterpret_cast<T*>(&data); } const T* operator -> () const { return getPointer(); } const T& operator * () const { return get(); } const T* operator & () const { return getPointer(); } const T* getPointer() const { return reinterpret_cast<const T*>(&data); } const T& get() const { return *reinterpret_cast<const T*>(&data); } private: std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type data; }; 

Now everything is a little easier:

 uninitialized<foo> f[N]; for (size_t i = 0; i < N; ++i) f[i].construct(i); for (const auto& fooref : f) fooref->bar(); // foo::~foo is called for you 
+1
source share

All Articles