I have a block of code where I am using unique_ptr.
class Abc {
public:
std::string msg;
Abc(std::string m) {
msg = m;
std::cout << "Constructor: " << msg << std::endl;
}
~Abc() {
std::cout << "Destructor: " << msg << std::endl;
}
};
int main() {
auto p = std::make_unique<Abc>(Abc(__func__));
}
But the destructor is called two times. Is there a way I can make it call the destructor only one time?
You're constructing a temporary Abc (i.e. Abc(__func__)) firstly, then pass it to std::make_unique, which constructs the underlying Abc from the temporary (via the move constructor of Abc); i.e. two Abc objects are constructed, then destructor are called twice too.
You can pass __func__ to std::make_unique directly, i.e. needn't to construct the temporary Abc from the beginning.
auto p = std::make_unique<Abc>(__func__); // constructs Abc via Abc::Abc(std::string) directly
You create two objects and see both of them destructed. Abc(__func__) is a temporary that gets destroyed at the end of the line in main.
Add a user defined move constructor to see how make_unique move constructs the object:
#include <string>
#include <memory>
#include <iostream>
class Abc {
public:
std::string msg;
Abc(std::string m) {
msg = m;
std::cout << "Constructor: " << msg << std::endl;
}
Abc(Abc&& other){
msg = other.msg + " moved";
std::cout << "Move Constructor: " << msg << "\n";
}
~Abc() {
std::cout << "Destructor: " << msg << std::endl;
}
};
int main() {
auto p = std::make_unique<Abc>(Abc(__func__));
}
Output:
Constructor: main
Move Constructor: main moved
Destructor: main
Destructor: main moved
Related
Some background
Today I saw, in the body of a function kaboom, a local shared_ptr pointing to a *global object and, being captured by reference and its pointee returned by reference by a lambda, i.e. [&local]() -> auto& { return *local; }; this lambda was stored somehow for further use after the function kaboom returned.
As soon as I saw this, I thought the code was invoking undefined behavior. I tried to make a minimal example to support my claim, and came up with the following.
#include <iostream>
#include <memory>
#include <functional>
#include <vector>
struct Resource {
const int i{3};
};
std::shared_ptr<Resource> global = std::make_unique<Resource>();
auto getSharedStuff() {
return global;
}
std::vector<std::function<Resource&()>> actions{};
void kaboom() {
std::shared_ptr<Resource> local = getSharedStuff();
actions.push_back([&local]() -> auto& { return *local; });
}
int main() {
kaboom();
std::cout << global->i << std::endl;
std::cout << actions[0]().i << std::endl;
}
The simple fact that the 2 couts give 3 and 0 respectively is proof for me that I'm observing UB (3 is correct, and 0 could have been anything, including 3, but I've been lucky that it was not 3, so the UB is well manifest).
Good.
The code I'm curious about
But before getting there, an intermediate version of the repro above was this:
#include <iostream>
#include <memory>
#include <functional>
#include <vector>
struct Resource {
Resource(Resource const&) = delete;
Resource(Resource&&) = delete;
Resource() { std::cout << this << "'s ctor" << std::endl; }
~Resource() { std::cout << this << "'s dtor" << std::endl; }
void operator()() { std::cout << this << "'s operator()" << std::endl; }
};
std::shared_ptr<Resource> global = std::make_unique<Resource>();
auto getSharedStuff() {
return global;
}
std::vector<std::function<Resource&()>> actions{};
void kaboom() {
std::shared_ptr<Resource> local = getSharedStuff();
actions.push_back([&local]() -> auto& { return *local; });
}
int main() {
kaboom();
std::cout << "---" << std::endl;
actions[0]()();
}
which can result in this output
0xc602b0's ctor
---
0x7f0f48f7f4a0's operator()
0xc602b0's dtor
I'm kind of ok with this, as actions[0]()() is dereferencing a destroyed shared_ptr and calling operator() on the screwed up result, so I accept that this can be screwup too.
What's funny, though, is that removing std::cout << "---" << std::endl; makes UB less manifest, as the output becomes something like this:
0xce92b0's ctor
0xce92b0's operator()
0xce92b0's dtor
So my question is: how can a "simple" line as std::cout << "---" << std::endl; affect this way the manifestation of UB?
I'm calling std::transform with a lambda that takes by reference and gives back a reference to the vector element. However, according to my program output, the copy constructor is called and the objects are NOT the same.
Code:
#include <algorithm>
#include <iostream>
#include <vector>
class Math
{
private:
int val_ = 5;
public:
Math(const Math& m) {
std::cout << "Copy constructor, our address: " << this << ", his address: " << &m << std::endl;
}
Math(int val) : val_(val) {
std::cout << "Object constructed with " << val << std::endl;
}
};
int main()
{
std::vector<Math> v_math = { { 5 }, { 10 } };
std::transform(
begin(v_math),
end(v_math),
begin(v_math),
[](const Math& m)-> const Math& {
return m;
});
}
Output (Godbolt):
Object constructed with 5
Object constructed with 10
Copy constructor, our address: 0x23d7ec0, his address: 0x7fff9dc499a8
Copy constructor, our address: 0x23d7ec4, his address: 0x7fff9dc499ac
So three things are unclear to me right now:
Why are the objects different? Shouldn't they be the same?
Why is one object's address bigger than the other? Is this because the copied-to object remains on the stack which has offset-pointers?
How can I avoid copy construction as well (actually I just "misuse" std::transform for a declarative way of invoking a lambda on every std::vector element)?
The copies have nothing to do with your usage of std::transform. They happen when you construct your v_math std::vector, because you're using a std::initializer_list constructor, which forces copies during construction.
In your std::transform call, operator=(const Math&) is called, change your code to the following to see this.
class Math
{
private:
int val_ = 5;
public:
Math(const Math& m) {
std::cout << "Copy constructor, our address: " << this << ", his address: " << &m << std::endl;
}
Math(int val) : val_(val) {
std::cout << "Object constructed with " << val << std::endl;
}
Math& operator=(const Math& other) {
val_ = other.val_;
std::cout << "Operator=(const Math&) called!\n";
return *this;
}
};
int main()
{
std::vector<Math> v_math = { { 5 }, { 10 } };
std::cout << "After constructing v_math!\n";
std::transform(
begin(v_math),
end(v_math),
begin(v_math),
[](const Math& m)-> const Math& {
return m;
});
std::cout << "After std::transform call!\n";
}
I am having difficulties while defining the copy constructor of my class TextListener. The class TextListener bind a method callback using this keyword. Please see the complete code below:
#include <iostream>
#include <ros/ros.h>
#include <std_msgs/String.h>
class TextListener {
private:
std::string _text;
ros::Subscriber _subscriber;
public:
TextListener() {
std::cout << "[" << this << "] deafult constructor called" << std::endl;
}
TextListener(const TextListener &other)
: _subscriber(other._subscriber), _text(other._text) {
std::cout << "[" << this << "] copy constructor called" << std::endl;
}
TextListener &operator=(const TextListener &other) {
std::cout << "[" << this << "] copy assignment called" << std::endl;
_subscriber = other._subscriber;
_text = other._text;
return *this;
}
TextListener(ros::NodeHandle &nh, const std::string &topicName) {
std::cout << "[" << this << "] constructor called" << std::endl;
_subscriber = nh.subscribe(topicName, 1, &TextListener::callback, this);
}
void callback(const std_msgs::String::ConstPtr &msg) { _text = msg->data; }
std::string &getText() { return _text; }
~TextListener() {
std::cout << "[" << this << "] destructor called" << std::endl;
}
};
To test the above class, I created an instance of it, which works without any problem. However, when I create a new instance and assign this instance to the new instance, the new instance doesn't work. Below is the code snippet:
int main(int argc, char **argv) {
ros::init(argc, argv, "tet_listener");
ros::NodeHandle nh;
std::string topicName = "chatter";
TextListener listener(nh, topicName);
TextListener copyListener = listener;
ros::Rate loop_rate(1);
while (ros::ok()) {
ROS_INFO("I heard: [%s]", copyListener.getText().c_str());
ros::spinOnce();
loop_rate.sleep();
}
return 0;
}
The method getText() doesn't have any value. See below the output:
[0x7ffc5698a2b0] constructor called
[0x7ffc5698a2d0] copy constructor called
[ INFO] [1549031938.250136695]: I heard: []
[ INFO] [1549031939.250183378]: I heard: []
[ INFO] [1549031940.250170333]: I heard: []
[ INFO] [1549031941.250176834]: I heard: []
^C[0x7ffc5698a2d0] destructor called
[0x7ffc5698a2b0] destructor called
I guess that the copy constructor is missing something. How to define copy constructor when keyword "this" is used inside constructor?
You need two Subscribers, one that notifies the original TextListener object, and one the that notifies the copy TextListener
You do actually have two Subscribers, but as the one in the copy TextListener is a copy of the one in the original, they both update the original TextListener's _text member.
I can't see a better way than keeping a reference to the NodeHandle in the TextListener, and having the copy constructor re-subscribe to the NodeHandle instead of copying the original object's subscription (which is calling the original object's callback).
I'm trying to understand when the deconstructor of a functor (i.e. a class with () operator) is called when that functor is passed to a thread. But in the following example, the constructor is called for once but the deconstructor is called for three times?
According to
What are the missing (two) calls to the constructor? Is it copy or move?
If the move constructor is called, how can write the deconstructor so that it won't destroy the resources being moved? Imagine I open a file run() and close it in the ~run(), calling it three times causes a problem of course.
Example:
#include <iostream>
#include <thread>
using namespace std;
class run {
public:
run() { cout << "in run()" << endl; }
~run() { cout << "in ~run()" << endl; }
void operator()() {};
};
int main() {
run thread_r;
thread t(thread_r);
t.join();
}
Gives output:
in run()
in ~run()
in ~run()
in ~run()
Rule of 5, 3 and zero.
If you define a destructor, the compiler will still generate a default copy constructor and assignment operator.
Unfortunately, if you've defined a destructor it implies that you have some special handling around resource deallocation, so the default copy and assignment code will be plain wrong.
It is good practice, by which I mean "always do it, no excuses", to provide at least copy constructor and assignment operator, even if you delete them.
If you're going to supply these, you may as well go ahead and write correct move operators too.
#include <iostream>
#include <thread>
using namespace std;
class run {
public:
run() { cout << "in run()" << endl; }
run(const run&) { cout << "copied()" << endl; }
run(run&&) { cout << "moved()" << endl; }
run& operator=(const run&) { cout << "copy-assigned()" << endl; return *this; }
run& operator=(run &&) { cout << "move-assigned()" << endl; return *this; }
~run() { cout << "in ~run()" << endl; }
void operator()() {};
};
int main() {
run thread_r;
thread t(thread_r);
t.join();
}
example output:
in run()
copied()
moved()
in ~run()
in ~run()
in ~run()
Here's an updated version to help explain what's happening in the constructors and destructors:
#include <iostream>
#include <thread>
#include <vector>
using namespace std;
class run {
public:
run()
: lifetime("constructed")
{
cout << lifetime << endl;
}
run(const run& other)
: lifetime("copied from " + other.lifetime)
{
cout << lifetime << endl;
}
run(run&& other)
: lifetime("move-constructed from " + other.lifetime)
{
other.lifetime = "[zombie] - " + other.lifetime;
cout << lifetime << endl;
}
run& operator=(const run& other)
{
lifetime = "copy assigned from " + other.lifetime + ", was once " + lifetime;
cout << lifetime << endl;
return *this;
}
run& operator=(run &&other)
{
lifetime = "move-assigned from " + other.lifetime + ", was once " + lifetime;
other.lifetime = "[zombie] - " + other.lifetime;
cout << lifetime << endl;
return *this;
}
~run()
{
lifetime = "lifetime ending: " + lifetime;
cout << lifetime << endl;
}
void operator()() {};
std::string lifetime;
};
int main() {
run thread_r;
thread t(thread_r);
t.join();
}
sample output:
constructed
copied from constructed
move-constructed from copied from constructed
lifetime ending: [zombie] - copied from constructed
lifetime ending: move-constructed from copied from constructed
lifetime ending: constructed
For anyone not sure about the exact behaviour of copy constructors and move-constructors, it would be a good idea to play with this code in a debugger until it becomes clear.
When I run the following program, the destructor is called twice and I'm trying to understand why?
#include <iostream>
#include <vector>
#include <algorithm>
class sample
{
public:
sample() { std::cout << "Constructor " << std::endl; }
~sample() { std::cout << "Destructor" << std::endl; }
void operator()(int i)
{
std::cout << i << " , " << std::endl;
}
};
int main()
{
std::vector<int> iNumbers;
for ( int i = 0 ; i < 5 ; ++i)
iNumbers.push_back(i);
std::for_each(iNumbers.begin() , iNumbers.end() , sample() );
}
The output is as folllows
Constructor
0 ,
1 ,
2 ,
3 ,
4 ,
Destructor
Destructor
Classic rule of three violation. Try this:
#include <iostream>
#include <vector>
#include <algorithm>
class sample
{
public:
sample() { std::cout << "Constructor " << std::endl; }
sample(const sample&) { std::cout << "Constructor (copy)" << std::endl; }
~sample() { std::cout << "Destructor" << std::endl; }
sample& operator=(const sample&) { return *this; }
void operator()(int i)
{
std::cout << i << " , " << std::endl;
}
};
int main()
{
std::vector<int> iNumbers;
for ( int i = 0 ; i < 5 ; ++i)
iNumbers.push_back(i);
std::for_each(iNumbers.begin() , iNumbers.end() , sample() );
}
Output is:
Constructor
0 ,
1 ,
2 ,
3 ,
4 ,
Constructor (copy)
Destructor
Destructor
The reason is that std::for_each takes its argument by value, and this results in a copy of the argument you provide being made.
Therefore, the destruction of the temporary you create by doing sample() will be responsible for one of those two destruction messages (the last one, since the temporary is destructed after the evaluation of the full expression that creates it).
The first destruction message, on the other hand, comes from the destruction of the copy that std::for_each is working on.
std::for_each will take the function object by value, causing it to be copied. So one destructor is called for the temporary object created by sample() and the other for the copy.
If you wrote a copy constructor, you would see that the functor is copied into the algorithm. Both copies are then destructed. There is a potential for the functor to be returned and there would be 3 copies, so one of the copies is being elided.