queue of unique_ptr issue

Started by
10 comments, last by Khatharr 8 years, 1 month ago

Hi,

I'm building a simple engine, and my Node class has a member


queue<unique_ptr<Action>> m_actions

that maintains a queue of actions to be processed by this node. It also has a functions to add another action to perform:


inline void Node::addAction (std::unique_ptr<Action> action) {
    action ->setTarget(this);
    m_actions. push (std::move(action));
}

As you can see, I'm using move semantics to pass the ownership of the action to the Node. This seems to work fine in Visual Studio, but then I tried to build this in Xcode and I'm getting the following error:

/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/memory:1466:36: No matching constructor for initialization of 'std::__1::unique_ptr<Action, std::__1::default_delete<Action> >'

which seems to imply that for some reason the unique_ptr is getting copied somewhere down the line. Does anyone know what is going on here and the reason of the difference behaviours for the two compilers?

Thanks!

Fabrizio

Advertisement
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/memory:1466:36: No matching constructor for initialization of 'std::__1::unique_ptr >'

which seems to imply that for some reason the unique_ptr is getting copied somewhere down the line. Does anyone know what is going on here and the reason of the difference behaviours for the two compilers?

How did you reach that decision? This is a compiler error, the program isn't running at this point in time, it doesn't even have any pointer instance currently.

In particular, this error is a template instantiation error. unique_ptr is implemented using a template, and apparently xcode expects a certain constructor to be available in the template that the template code of the compiler library doesn't provide.

In general, xcode is more precise in interpreting the standard, and/or doesn't provide many bells and whistles to make things work more smoothly.

I don't know the error, but first thing you should do is throw it in a search engine and see what it comes up with. 99% chance that someone has run into it in the past, and figured out what to do. Secondly, some statement in your code indirectly triggers need for the non-existing constructor. Check that area carefully. Is it really as the standard wants it?

You can also try to make a very small example that demonstrates the problem, perhaps while experimenting with it, you find the cause, or else, you have something you can show to other people and ask about.

Assuming this is the exact code you've been using, the argument you are taking is a unique pointer by value. Any statement calling this function will have to pass a unique pointer by value, i.e. copy it.

I'll take an educated guess and say marking it as inline causes this difference in behaviour. The inlining would give the ability to replace the function argument with the original statement/variable, thus never having to copy it. The behaviour may differ because of differences in rules for when inlining is possible. I can't say this for sure though, especially since I haven't encountered it myself :D

You could either pass the unique pointer by reference, or by right-value reference and move semantics upon calling the function. My preference would go to the latter, since with a left-value reference it has side-effects for the caller side (it can no longer use the unique pointer).

/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/memory:1466:36: No matching constructor for initialization of 'std::__1::unique_ptr >'

which seems to imply that for some reason the unique_ptr is getting copied somewhere down the line. Does anyone know what is going on here and the reason of the difference behaviours for the two compilers?

How did you reach that decision? This is a compiler error, the program isn't running at this point in time, it doesn't even have any pointer instance currently.


I suspect he had in mind the fact that unique_ptr isn't copyable - and that fact is enforced by the compiler. The constructor that isn't available is the copy constructor.

I suspect he had in mind the fact that unique_ptr isn't copyable - and that fact is enforced by the compiler. The constructor that isn't available is the copy constructor.
I realized he was trying to copy the value when I read the response of AthosVG, I was too focussed on the error message, and totally missed that :(

Not sure how you derived it being the copy-constructor from the error message (I have no access to xcode files).


Not sure how you derived it being the copy-constructor from the error message (I have no access to xcode files).

Yay for obtuse C++ compile errors! The (deleted) copy constructor needs to be invoked to pass the parameter by value, and the error message references a missing constructor:


 No matching constructor for initialization of 'std::__1::unique_ptr<Action, std::__1::default_delete<Action> >'

I have never used xcode before. Are there any more lines to the error message? Usually, in Visual Studio or gcc, if there is an error like this, it would give some context about where it was trying to copy the unique_ptr. People shouldn't have to blindly guess about this.


Yay for obtuse C++ compile errors! The (deleted) copy constructor needs to be invoked to pass the parameter by value, and the error message references a missing constructor:

You do not need a copy constructor to pass a parameter by value.


You do not need a copy constructor to pass a parameter by value.

Then how would it be copied?


You do not need a copy constructor to pass a parameter by value.

Then how would it be copied?

Move construction is used when an rvalue or xvalue is passed by value and the type has a move constructor.

@OP: Are you calling this function like Node::addAction(std::move(upAction))? Otherwise "upAction" (or whatever unique_ptr variable you're passing into the function) should be seen as an lvalue by the compiler and copy construction will be attempted (Visual C++ might be allowing it because the function is inline).


#include <iostream>
#include <memory>

class Foo {
public:
  Foo(int i) : ip(std::make_unique<int>()) {
    *ip = i;
  }

  Foo(Foo&& other) {
    ip = std::move(other.ip);
  }

  void show() const {
    std::cout << *ip << "\n";
  }

private:
  std::unique_ptr<int> ip;
};

void test(Foo obj) {
  obj.show();
}

int main() {
  Foo f(42);
  test(f);
  f.show();
  std::cin.get();
}

main.cpp(28): error C2280: 'Foo::Foo(const Foo &)': attempting to reference a deleted function
void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

This topic is closed to new replies.

Advertisement