1

The following code does not compile (at least in the versions of g++/clang I tried). godbolt link

struct T {
    std::unique_ptr<double> p;

    T() {}
    T(const T&) {}
    T(T&&) {}
};

struct X {
    T t;
    std::vector<std::unique_ptr<int>> f;
};

int main()
{
    std::vector<X> y;
    X x;
    y.emplace_back(std::move(x));
}

Specifically, the compilers seem to complain about a call to a deleted copy constructor on vector<unique_ptr<int>> which doesn't make sense to me.

The requirements seem to more or less say that emplace_back should work if there is a move constructor. Since there are no user-declared constructors for X and also no members / base classes that can't be moved from, I believe that a move constructor should be implicitly declared and not deleted.

Some 'fixes':

Could someone explain why the original code is ill-formed? And why the 'fixes' (mostly the first 3 and especially the 3rd) make the code compile?

Lawrence
  • 862
  • 1
  • 7
  • 15
  • 2
    Fix #5: Make `T`s move-constructor noexcept. – tkausl Jun 22 '18 at 04:58
  • @tkausl yes... I forgot about that caveat for vector operations... it doesn't seem to explain 'fix' 2 or 3 though. – Lawrence Jun 22 '18 at 05:04
  • @Praetorian yes I forgot about the move noexcept qualifications but the question you linked doesn't answer my full question either. From the emplace_back reference: 'If T's move constructor is not noexcept and is not CopyInsertable into *this, vector will use the throwing move constructor.' – Lawrence Jun 22 '18 at 05:13
  • 1
    #2 and #3 is somewhat more subtle, I assume vector chooses move even if its not noexcept if copy is impossible and the vector of non-copyable objects reports back as being copyable and fails when it actually tries to copy it. Not sure what exactly is going on interally though. – tkausl Jun 22 '18 at 05:16
  • 1
    By the way, this might seem like a problem arising from the emplace_back trying to move in the object, it isn't. Its about the vector making sure it's large enough and reserve more space if needed. – tkausl Jun 22 '18 at 05:18
  • 2
    @Lawrence That clause doesn't apply to `X`, it is copyable and has a throwing move constructor so `vector` will attempt to copy it. Adding the extra `unique_ptr` to `X` makes the class non-copyable, so `vector` is forced to use the move constructor, throwing or not. – Praetorian Jun 22 '18 at 05:20

0 Answers0