7

I have a fixed number of objects of class T that are non-copyable and non-default-constructible. Since the size is fixed I would like to use an array-ish container like std::array instead of unique_ptr or vector. I would like to avoid the additional layer of indirection if I can help it.

How do I initialize an std::array<T, 2>? Using array<T, 2> {T(...), T(...)} results in an error about deleted copy constructor. Using array<T, 2> {move(T(...)), move(T(...))} does not force the array elements to use the move constructor. If std::array<T, 2> inherently does not work, what else can I do without resorting to an additional layer of indirection or manual memory management techniques like placement-new?

Joshua Chia
  • 1,760
  • 2
  • 16
  • 27
  • Sounds to me like all instances of T should be accessed only via smart pointers. `std::array` of unique/shared ptrs to T, etc... – Sam Varshavchik Jul 29 '16 at 02:01
  • @SamVarshavchik, Yet you can use `std::vector` with move-only, non-default-constructible types just fine. – chris Jul 29 '16 at 02:04
  • What I want to accomplish can in-principle be accomplished, albeit with messy and hard-to-read techniques like placement new. I know a vector would be simple but it gives me the additional overhead that I set out to avoid that in-principle is completely avoidable. – Joshua Chia Jul 29 '16 at 02:06
  • Have you considered using a tuple? – happydave Jul 29 '16 at 02:09
  • I want to access the elements with an index. – Joshua Chia Jul 29 '16 at 02:11
  • Somewhat related: [constructor - Inlining an array of non-default constructible objects in a C++ class - Stack Overflow](https://stackoverflow.com/questions/2707923/inlining-an-array-of-non-default-constructible-objects-in-a-c-class) – user202729 Feb 12 '22 at 11:06

2 Answers2

5

No need for extra stuff, just initialize it directly:

class Foo {
public:
    Foo() = delete;
    Foo(int,char) {}

    Foo(Foo const &) = delete;
    Foo & operator = (Foo const &) = delete;
};
    std::array<Foo, 2> arr {{ {1, '1'}, {2, '2'} }};

DEMO

O'Neil
  • 3,790
  • 4
  • 16
  • 30
  • LOL one more set of braces... that's what I forgot. +1. – Barry Jul 29 '16 at 02:37
  • It seems to work for me. Where can I got to learn the meaning of these layers of braces for the std::array? – Joshua Chia Jul 29 '16 at 04:11
  • 2
    @JoshuaChia [stl - Why is the C++ initializer_list behavior for std::vector and std::array different? - Stack Overflow](https://stackoverflow.com/questions/11400090/why-is-the-c-initializer-list-behavior-for-stdvector-and-stdarray-differen) – user202729 Feb 12 '22 at 11:06
0

My example is not the best but it works.. Just create a function that make_array and have it create the instances for you..

http://ideone.com/fxAO3t

#include <array>
#include <iostream>

class Foo
{
    public:
        Foo(int)
        {

        }

        Foo(const Foo &) = delete;

        Foo(Foo &&)
        {
            std::cout<<"Moved\n";
        }
};

template<class... Type>
constexpr std::array<typename std::common_type<Type...>::type, sizeof...(Type)> make_array(Type&&... t)
{
    return {std::forward<Type>(t)...};
}

int main() {
    auto arr = make_array(Foo{1}, Foo{2});
    return 0;
}

As pointed out in the comments, you can do std::array<Foo, 2> arr = {Foo{1}, Foo{2}}.

I noticed you were trying to move in your post. Are you sure your class is moveable?

Brandon
  • 22,723
  • 11
  • 93
  • 186
  • If `Foo` is moveable, you don't need the function. Just `std::array arr{1, 2};` is sufficient. – Barry Jul 29 '16 at 02:25
  • Ahh you're right. OP was trying to do exactly what you just suggested. He/She was doing `std::move(Foo)`. – Brandon Jul 29 '16 at 02:29