c++ attempting to reference deleted function - c++

I have been playing around with std::unique_ptr and the std::for_each algorithm to learn them and I then received this error "attempting to reference a deleted function" when I am attempting to move some variables from one container (std::map) to another.
This code is currently executed in a member function. Foo is just a generic class.
std::for_each(m_list1.begin(), m_list1.end(),
[&](std::pair<std::size_t,std::unique_ptr<Foo>> data_pair)
{
m_list2[data_pair.first] = std::unique_ptr<Foo>(std::move(data_pair.second));
});
m_list1.clear();
I tried various things but the problems still persists. I then tried using range-based for instead and suddenly it works.
for (auto& data_pair : m_list1)
{
m_list2[data_pair.first] = std::unique_ptr<Foo>(std::move(data_pair.second));
}
m_list1.clear();
What I want to know is why the second code executed with no problem, while the first code produced the error.
If you need more specific information, Just ask. If there's bad practice in my coding style, please advice on how to make it better.

There are two errors in your for_each code. First, map::value_type is pair<const Key, Value>. Second, your lambda expression is taking the argument by value, which means it attempts to copy the unique_ptr, hence the error. To fix it, take the argument by reference.
[&](std::pair<const std::size_t, std::unique_ptr<Foo>>& data_pair)
// ^^^^^ ^^^
{
m_list2[data_pair.first] = std::unique_ptr<Foo>(std::move(data_pair.second));
}
A better option is to not mention those types explicitly, instead use decltype
[&](decltype(m_list1)::value_type& data_pair)
{
m_list2[data_pair.first] = std::unique_ptr<Foo>(std::move(data_pair.second));
}
Now, your range-based for worked because you were binding the elements of the map to a reference by using for(auto& data_pair : m_list1). You'd have run into the same error as before if you'd instead used for(auto data_pair : m_list1) because that'd have attempted to make a copy of the elements.

Related

How to pass a std::function or a function pointer into qtconnect?

This is mainly to clean up a bunch of code from my constructor. I have around 20+ lines of connect(object, func1, this, func2) in the constructor alone and I am trying to clean up the code by having a std::vector<std::tuple<QObject*,std::function<void()>,std::function<void>>>> connections;
It would work out quite nicely if I could do something like:
std::vector<std::tuple<QObject*,std::function<void()>,std::function<void>>>> connections = {
std::make_tuple(mySlider, std::bind(&QSlider::sliderReleased,mySlider, std::bind(&Foo::onSliderChanged,this)),
.
.
.
};
And then call it like this:
for(auto &&e : connections)
connect(std::get<0>(e),std::get<1>(e),this,std::get<2>(e));
However, when I do this I get an error that there is a substitution failure and a std::function<void()> cannot be converted into a function pointer. So decide to change it up and create actual function pointers like the following:
typename void(Foo::*fooFunc)();
typename void(QSlider::*sliderFunc)();
std::vector<std::tuple<QObject*,sliderFunc,fooFunc>> sliderConnections = {
std::make_tuple(mySlider, &QSlider::sliderReleased, &Foo::onSliderChanged),
.
.
.
};
And same thing, I then try to call it:
for(auto &&e : sliderConnections)
connect(std::get<0>(e),std::get<1>(e),this,std::get<2>(e));
However this also provides a similar error where there are no conversions. Which doesn't make any sense because now I am actually using a function pointer. Which according to the connection documentation it should be able to take a function pointer to connect them. So either I am passing it in incorrectly. Or what I am trying to achieve is not possible.
Any help would be appreciated!
After looking at G.M's comment I realized they were correct. A QObject* is not a QSlider* and therefore when trying to call the function QSlider::sliderReleased it couldn't connect the two because QObject does not have a slider. So once I changed that in the vector of tuples the code compiled just fine.
ex:
typedef void(Foo::*fooFunc)();
typedef void(QSlider::*sliderFunc)();
typedef void(QSpinBox::*spinFunc)();
const std::vector<std::tuple<QSlider*, sliderFunc, fooFunc>> sliderConnections = {
std::make_tuple(slider1, &QSlider::sliderReleased, &Foo::onSlider1Changed),
std::make_tuple(slider2, &QSlider::sliderReleased, &Foo::onSlider2Changed),
std::make_tuple(slider3, &QSlider::sliderReleased, &Foo::onSlider3Changed)
};
const std::vector<std::tuple<QSpinBox*, spinFunc, fooFunc>> spinConnections = {
std::make_tuple(spin1, &QSpinBox::editingFinished, &Foo::onSpin1Changed),
std::make_tuple(spin2, &QSpinBox::editingFinished, &Foo::onSpin2Changed),
std::make_tuple(spin3, &QSpinBox::editingFinished, &Foo::onSpin3Changed)
};
These will be private members in whatever class you are in charge of. And then in the constructor, instead of having 6 lines of connect(object,SIGNAL,object,SLOT), you can then put them into a function and call them like:
for(auto && tup : sliderConnections)
connect(std::get<0>(tup),std::get<1>(tup),this,std::get<2>(tup));
This successfully connects all the objects to their appropriate functions. Again, it's personal preference. I was just wondering if there was a way and G.M pointed me in the correct direction.

Prevent v8::Local value from being garbage collected

I have a function that stores the value of an argument to an std::vector<v8::Local<v8::Value>> property of a C++ class exposes as an ObjectWrap like this:
NAN_METHOD(MyObject::Write) {
MyObject* obj = Nan::ObjectWrap::Unwrap<MyObject>(info.This());
obj->data.push_back(info[0]);
}
However, when I try to read back the value from another C++ function, the value is lost, and becomes undefined.
I'm passing a number to MyObject::Write, and I can confirm info[0]->IsNumber() returns true before pushing it to the vector, however when reading it back, the value it not a number, and in fact returns false for all the types I tested using Is<Type> methods from v8::Value, but still returns true for BooleanValue().
My guess is that the variable is being garbage collected after MyObject::Write returns, however I have no idea how to prevent this from happening.
I'm currently trying to initialise the value as a Persistent value. I tried the following attempts without success:
Nan::CopyablePersistentTraits<v8::Value>::CopyablePersistent p;
Nan::Persistent<v8::Value> persistent(info[0]);
Nan::CopyablePersistentTraits::Copy(persistent, p);
And:
v8::Isolate *isolate = info.GetIsolate();
v8::Persistent<v8::Value, v8::CopyablePersistentTraits<v8::Value>> persistent(isolate, info[0]);
But getting tons of C++ errors.
I was running into problems untangling this mess myself. There's a lot of template stuff going on here that we both missed. Here was the solution I found most readable:
// Define the copyable persistent
v8::CopyablePersistentTraits<v8::Value>::CopyablePersistent p;
// Create the local value
auto val = v8::Local<v8::Value>::New(
v8::Isolate::GetCurrent(), //< Isolate required
v8::Integer::New(v8::Isolate::GetCurrent(), v) //< Isolate required
);
// Reset() is a TEMPLATE FUNCTION, you have to template it with the same
// template type parameter as the v8::Local you are passing
p.Reset<v8::Value>(v8::Isolate::GetCurrent(), val); //< Isolate required
By "info" I assume you are referring to a v8::FunctionCallbackInfo reference. If so the above code would collapse to the following:
void SomeFunc(v8::FunctionCallbackInfo<v8::Value>& info) {
v8::CopyablePersistentTraits<v8::Value>::CopyablePersistent p;
p.Reset<v8::Value>(info[0]);
}
Because the persistent is now copyable you can do things like store it inside a standard library container. This was my use case. This is an example of storing a value in a vector:
std::vector<v8::CopyablePersistentTraits<v8::Value>::CopyablePersistent> vect;
void AccumulateData(v8::FunctionCallbackInfo<v8::Value>& info) {
v8::CopyablePersistentTraits<v8::Value>::CopyablePersistent p;
p.Reset<v8::Value>(info[0]);
vect.push_back(p);
}
I hope this helps someone out there.
If you plan on storing v8 values in C++, you need to make them persistent instead of local so they're independent of handle scope and not garbage-collected when the handle scope is released.
Nan has version-independant wrappers for v8::Persistent and Co. Because of using inside std::vector<>, you'll also need to initialize Nan::Persistent with Nan::CopyablePersistentTraits so it becomes copyable (or make an own reference-counted container for it).

How to store inside a queue a unique_ptr of object which is located inside a vector

So I am building a simulator in order to simulate some load balancing algorithms. I have created 2 vectors of Cores and Dispatchers as shown below:
std::vector<std::unique_ptr<Dispatcher> > vDisp;
std::vector<std::unique_ptr<Core> > vCore;
The class dispatcher has a queue for the cores in order to assign to them the jobs.
std::queue<Core> disp_core_queue;
Plus I have some functions in order to handle this queue:
void add_core_q(Core& p){ disp_core_queue.push(p); }
Core get_core_q(){ return disp_core_queue.front(); }
When the program initializes I populate the cores and disps like this:
for (auto i=0; i<dispNumb; ++i)
{
vDisp.push_back(std::unique_ptr<Dispatcher> (new Dispatcher));
std::cout<<"Disp n."<<i<<" Created"<<std::endl;
}
My problem is that I cannot get a Core from the vector and store it inside a Dispatcher's queue. I have tried many ways but it seems C++ punishes me for various reasons. My last try was this one from inside the Dispatcher:
int kore = random_core();
this->add_core_q(vCore.at(kore));
Which gave this error in compile time:
error: no matching function for call to 'Dispatcher::add_core_q(_gnu_cxx::__alloc_traits > >::value_type&) '
candidate is:
void Dispatcher::add_core_q(Core&)
no known conversion for argument 1 from '__gnu_cxx::__alloc_traits > >::value_type {aka std::unique_ptr}' to 'Core&'
If anyone could give me a hint I would greatly appreciate it. Thanks in advance.
The function signature for add_core_q is taking Core&.
You are passing in a std::unique_ptr.
Your Core objects are stored inside unique_ptr's yet your add_core_q method requires a Core reference.
You could get the raw pointer from the unique_ptr and dereference it which would allow you to do this:
add_core_q(*(vCore[0]));
However you're also going to have a problem with your get_core_q method since it returns a copy of the Core object rather than a reference to the Core stored in the unique_ptr.
Personally I'd just pass around pointers rather than dereferencing things. So you'd change your add_core_q method to accept a raw pointer:
void add_core_q(Core* p){ disp_core_queue.push(p); }
Which you would use like this:
add_core_q(vCore[0].get());
You'd also have to change your queue to store pointers rather than the objects themselves:
std::queue<Core*> disp_core_queue;
And you'll need to change the return type of your get method to a pointer.
Core* get_core_q(){ return disp_core_queue.front(); }
Though if you're more comfortable with references you could return a reference instead:
Core& get_core_q(){ return *(disp_core_queue.front()); }

Method returning std::vector<std::unique_ptr<Object>>

As a continuation of a: Thread, I came across a problem with
writing a method of a class which returns:
std::vector<std::unique_ptr<Object>>
I get compiler errors when such a return type is written. There is some problem with delete operand or something ...
Generally, I've wanted to write a method which initializes vector and returns it.
Could anyone help me how to write it?
EDIT:
I Get:
attempting to reference a deleted function h:\pliki programów (x86)\microsoft visual studio 12.0\vc\include\xmemory0
Here I have the following code snippet. Can I create such a method like this?
std::vector<std::unique_ptr<Object>> Class::TestMethod(int param)
{
std::vector<std::unique_ptr<Object>> array;
auto day = std::make_unique<Object>();
array.push_back(day);
return array;
}
Your error is actually coming from:
array.push_back(day);
This tries to put a copy of day in the vector, which is not permitted since it is unique.
Instead you could write array.push_back( std::move(day) ); however the following would be better, replacing auto day...:
array.emplace_back();
The copy constructor of std::unique_ptr is deleted. That causes a problem in the line:
array.push_back(day);
Use
array.push_back(std::move(day));

Is it possible to store unique_ptr in a QList of QPairs?

To avoid a lot of unnecessary copying I'm trying to store unique_ptr's in a list of pairs. I'm using a simple class Test which takes a QString;
I'm using VS2013 with Qt5.4
using std::unique_ptr;
QList<QPair<unique_ptr<Test>, unique_ptr<Test>>> list;
auto a = std::make_unique<Test>("a");
auto b = std::make_unique<Test>("b");
// First make a pair
auto pair = qMakePair(std::move(a), std::move(b)); // Fails
// Error C2280 - attempting to reference a deleted function
Because of failure I tried:
QList<std::pair<unique_ptr<Test>, unique_ptr<Test>>> list;
auto pair = std::make_pair(std::move(a), std::move(b)); // Succes
list.append(std::move(pair)); // Fails
// Error C2280 - attempting to reference a deleted function
Because of failure I changed completely to STL containters:
std::list<std::pair<unique_ptr<Test>, unique_ptr<Test>>> list;
auto pair = make_pair(std::move(a), std::move(b)); // Succes
list.push_back(std::move(pair)); // Succes
This works. Is my conclusion correct that these Qt containers don't support move semantics and I have to use STL instead?
std::unique_ptr is not copyable, so nope for Qt containers.
Qt containers where created way before std::move (or even std::string) became a thing.
Maybe there will be better support in Qt6. It is poised to break a few things to integrate better with modern C++.
OTOH, you might as well use the std-containers if they work for you, unless you had some specific use case in mind?