0

Try the following code with native array, std::array and std::vector

typedef unique_ptr<int> UPtr;

UPtr[] f() // wrong, how to return a native array?
{
    UPtr a[] = { UPtr(new int(1)), UPtr(new int(2)) };
    return std::move(a);
}

std::array<UPtr, 2> g()
{
    std::array<UPtr, 2> a = { UPtr(new int(1)), UPtr(new int(2)) }; // compile ok but run wrong, 1 and 2 are not assigned
    return std::move(a); // wrong, call a deleted function
}

std::vector<UPtr> h()
{
    std::vector<UPtr> a = { UPtr(new int(1)), UPtr(new int(2)) }; // wrong, call a deleted function
    return std::move(a);
}

All failed. There are many problems here. How to fix them? Thanks a lot.

user1899020
  • 13,167
  • 21
  • 79
  • 154

1 Answers1

2

Since std:array<T, N> is an aggregate, it's as copyable or movable as its members permit. This means everything should work as intended. Indeed, the following code compiles fine with Clang, libc++ and -std=c++1y (the latter chosen for std::make_unique), and also in GCC 4.8 with libstdc++ if you spell out the make_unique calls:

#include <memory>
#include <array>

std::array<std::unique_ptr<int>, 2> f()
{
    std::array<std::unique_ptr<int>, 2> a = { {
        std::make_unique<int>(1), std::make_unique<int>(2) } };
    return a;
}

#include <iostream>

int main()
{
    auto a = f();
    std::cout << *a[0] << " " << *a[1] << "\n";

    for (auto const & p : f())
        std::cout << *p << "\n";
}

Note, though, that brace elision (especially in the context of direct-list-initialization) and aggregate initialization of movable-only types are new features of C++11 for which vendor support is evolving only slowly, so that bugs are not uncommon.

Also note that list-initialization (either direct- or copy-) of a std::vector<std::unique_ptr<int>> cannot work, since that one would require a constructor call that takes an std::initializer_list, which cannot handle movable-only types. By contrast, std::array works because list-initialization is aggregate initialization in that case.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • [Live demo](http://coliru.stacked-crooked.com/a/160ed235cd44020d) – Kerrek SB Jun 28 '14 at 12:40
  • Why use 2 braces {{ }}? – user1899020 Jun 28 '14 at 12:42
  • @user1899020: Added. It's called "brace elision", and nobody understands it (probably not even your compiler), so I chose to keep all the braces where they belong. A good compiler (Clang) will tell you what you need to do if you forget. – Kerrek SB Jun 28 '14 at 12:45
  • I am always confused about initializations. What is the outer braces for and inner braces for? Thanks. – user1899020 Jun 28 '14 at 13:05
  • @user1899020: I wasn't joking. Nobody understands brace elision. There's one brace pair for each object that's itself an aggregate. – Kerrek SB Jun 28 '14 at 13:08