Reputation: 23660
I need a container of elements that are neither copyable nor movable. These elements are not default constructible, but their constructors get identical arguments.
The size of the container does not change during it's lifetime. It should be as simple as a built-in array, but it's size is determined at run-time when the constructor is called.
Is there an easy way to implement that without the overhead of memory allocation and indirection incurred by using std::vector<std::unique_ptr<T>>
?
Upvotes: 9
Views: 2789
Reputation: 51
I was trying to do the same thing, and I'm using a simple workaround. What's wrong with this example?
class test{
const int a;
public:
test(int i): a(i) {} //no default constructor
};
//trick for static initializer
template <typename T> class defer_params: public T{
public:
defer_params(): T(1) {} //fixed params
};
//static array
//test list1[5]; //this doesn't work
defer_params<test> list2[5];
Regards, Gabriel
Upvotes: 0
Reputation: 5678
Here's a simple, yet incomplete solution under the assumption that each element is constructed with the same arguments. It uses placement new
to construct the elements in-place (see also this SO question):
#include <cstdlib>
#include <utility>
#include <new>
// sample structure, non-copyable, non-moveable, non-default-constructible
struct Foo
{
Foo() = delete;
Foo(const Foo&) = delete;
Foo& operator = (const Foo&) = delete;
Foo(Foo&&) = delete;
Foo& operator = (Foo&&) = delete;
Foo(int a, char b, double c) : m_a(a), m_b(b), m_c(c) { }
int m_a;
char m_b;
double m_c;
};
template <typename T>
struct MyArray
{
// Array ctor constructs all elements in-place using the
// provided parameters
template <typename... Args>
MyArray(std::size_t sz, Args&&... args)
: m_sz(sz),
m_data(static_cast<T*>(malloc(sz * sizeof(T))))
{
for (std::size_t i=0; i<m_sz; ++i)
{
new (&m_data[i]) T(std::forward<Args>(args)...);
}
}
~MyArray()
{
for (std::size_t i=0; i<m_sz; ++i)
{
m_data[i].~T();
}
free(m_data);
}
std::size_t m_sz;
T *m_data;
};
int main()
{
Foo foo(1, '2', 3.0);
std::size_t s = 5;
MyArray<Foo> foo_arr(s, 1, '2', 3.0);
}
Note that a few things are missing:
MyArray
's constructor.begin()
/end()
operators etc., for more convenience and to get the same behaviour as provided by the standard containers.m_sz
and m_data
private members.Upvotes: 3
Reputation: 7013
"Is there an easy way to implement that without the overhead of memory allocation and indirection incurred by using std::vector>?"
The overhead is so minimal, why do you care? This is almost certainly premature optimisation, and you're just going to make yourself a maintenance headache.
Upvotes: -2