Curious things with g++ (maybe also with other compilers?):
struct Object {
Object() { std::cout << "hey "; }
~Object() { std::cout << "hoy!" << std::endl; }
};
int main(int argc, char* argv[])
{
{
Object myObjectOnTheStack();
}
std::cout << "===========" << std::endl;
{
Object();
}
std::cout << "===========" << std::endl;
{
Object* object = new Object();
delete object;
}
}
Compied with g++:
===========
hey hoy!
===========
hey hoy!
The first type of allocation does not construct the object. What am I missing?
The first type of construction is not actually constructing the object. In order to create an object on the stack using the default constructor, you must omit the ()'s
Object myObjectOnTheStack;
Your current style of definition instead declares a function named myObjectOnTheStack which returns an Object.
Yet another example of the "most vexing parse". Instead of defining an object, you've declared a function named myObjectOnTheStack that takes no arguments and returns an Object.
Object myObjectOnTheStack();
is a forward declaration of a function myObjectOnTheStack taking no parameters and returning an Object.
What you want is
Object myObjectOnTheStack;
Related
I had a situation where I wanted to import a call after another call from the calling function. I decided to override a virtual destructor for the purpose:
#include <iostream>
struct type {
virtual ~type() {
std::cout << "ordinary" << std::endl;
}
void method() {
struct method_called : type {
virtual ~method_called() override {
std::cout << "method called" << std::endl;
}
};
this->~type();
new (this) method_called{};
}
};
int main() {
std::cout << "ordinary expected" << std::endl;
{
type obj;
}
std::cout << "method expected" << std::endl;
{
type obj;
obj.method();
}
std::cout << "method expected" << std::endl;
type* pobj = new type{};
pobj->method();
delete pobj;
}
It seems the overridden destructor is called only using dynamic allocation. Is this intended?
GCC godbolt.
this->~type();
Any dereference of any pointer pointing to the object or variable referring to the object that exists prior to this line is undefined behavior once you do this.
This includes the automatic storage destructor.
To avoid undefined behaviour in main after doing this, you'd have to call exit or similarly never return from the scope where the variable exists.
By the time the destructor is finished, the objects lifetime is over. Almost any use of the object after that triggers UB. You can reuse the storage:
new (this) method_called{};
This creates an distinct object in the storage that this refers to. If this storage has sufficient alignment and size, doing so is fine. It is extremely tricky to get right, because one of the few ways to safely get a pointer to this newly created object is by recording the return value to placement new like this:
auto* pmc = new (this) method_called{};
you don't do that.
{
type obj;
obj.method();
}
this is undefined behavior. The standard does not restrict what the program produced by your compiler does if this code is or would be executed at any point in your programs execution.
type* pobj = new type{};
pobj->method();
delete pobj;
so is this.
I had a situation where I wanted to import a call after another call from the calling function. I decided to override a virtual destructor for the purpose:
#include <iostream>
struct type {
virtual ~type() {
std::cout << "ordinary" << std::endl;
}
void method() {
struct method_called : type {
virtual ~method_called() override {
std::cout << "method called" << std::endl;
}
};
this->~type();
new (this) method_called{};
}
};
int main() {
std::cout << "ordinary expected" << std::endl;
{
type obj;
}
std::cout << "method expected" << std::endl;
{
type obj;
obj.method();
}
std::cout << "method expected" << std::endl;
type* pobj = new type{};
pobj->method();
delete pobj;
}
It seems the overridden destructor is called only using dynamic allocation. Is this intended?
GCC godbolt.
this->~type();
Any dereference of any pointer pointing to the object or variable referring to the object that exists prior to this line is undefined behavior once you do this.
This includes the automatic storage destructor.
To avoid undefined behaviour in main after doing this, you'd have to call exit or similarly never return from the scope where the variable exists.
By the time the destructor is finished, the objects lifetime is over. Almost any use of the object after that triggers UB. You can reuse the storage:
new (this) method_called{};
This creates an distinct object in the storage that this refers to. If this storage has sufficient alignment and size, doing so is fine. It is extremely tricky to get right, because one of the few ways to safely get a pointer to this newly created object is by recording the return value to placement new like this:
auto* pmc = new (this) method_called{};
you don't do that.
{
type obj;
obj.method();
}
this is undefined behavior. The standard does not restrict what the program produced by your compiler does if this code is or would be executed at any point in your programs execution.
type* pobj = new type{};
pobj->method();
delete pobj;
so is this.
My c++ is rusty, so while trying to improve some code I wrote a few days ago by changing some calls from passing a MyClass *const thing to Myclass& thing, I noticed that nothing complained about code that followed this contrived example.
#include <iostream>
class Foo {
public:
Foo() {
std::cout << "foo created" << std::endl;
}
~Foo() {
std::cout << "foo destroyed" << std::endl;
}
Foo(Foo& other) {
member = other.member;
std::cout << "foo copied" << std::endl;
}
bool member = false;
};
class Bar {
public:
Bar(Foo& foo) :foo_(foo) { }
Foo foo_; // **** HERE IS THE BUG this should be: Foo& foo_;
};
int main() {
Foo foo;
Bar barOne(foo);
Bar barTwo(foo);
foo.member = true;
std::cout << barOne.foo_.member << std::endl;
std::cout << barTwo.foo_.member << std::endl;
}
I really wanted to have one Foo object, but since I forgot the & I got three instead.
foo created
foo copied
foo copied
0
0
foo destroyed
foo destroyed
foo destroyed
adding the & I get the right result.
foo created
1
1
foo destroyed
Note: the Foo, constructors and destructor are just there to demonstrate what's happening.
I know is legal, but is there a compiler flag that would warn you if you declare an Object as a member variable? Is it a bad practice to store a reference in a member variable? I would not think it is, but like I said my c++ is rusty to say the least.
Update
To answer the question of what I was refactoring from. I was doing something similar to this. I was refactoring to references as everything I read about modern c++ says to prefer references rather than pointers.
class Bar {
public:
Bar(Foo const* foo) :foo_(foo) { }
Foo const* foo_;
};
int main() {
Foo foo;
Bar barOne(&foo);
Bar barTwo(&foo);
foo.member = true;
std::cout << barOne.foo_->member << std::endl;
std::cout << barTwo.foo_->member << std::endl;
}
I know is legal, but is there a compiler flag that would warn you if you declare an Object as a member variable?
I doubt there is such a flag. Objects of one type are stored as member variables of other types too many times and too many places for that flag to be useful.
Is it a bad practice to store a reference in a member variable?
No, it is not. However, you have to be aware of where you run into problems.
As long the life of the object that holds the reference ends before the life of the object to which it holds the reference ends, you will be fine. Otherwise, you end up holding on to a dangling reference. Using a dangling reference is cause for undefined behavior.
Storing object as a member of other object is prefectly fine.
Storing reference as a member is OK if you are sure that the object holding the reference is never going to outlive the referenced variable.
I was trying to answer this question, so I decided to create the following simple test case so that the OP could see by himself the memory leak.
#include<iostream>
class MyObject
{
public:
MyObject(){std::cout << "creation of my object" << std::endl;}
virtual ~MyObject(){std::cout << "destruction of my object" << std::endl;}
};
void processMyObject(MyObject foo)
{
}
int main()
{
processMyObject(*new MyObject());
return 0;
}
I compiled it :
g++ test.cpp -o test
And then, I saw an unexpected output :
creation of my object
destruction of my object
I have absolutly no idea of what is happening here. Could anyone explain to me ?
PS: I used g++ 4.6.3
Since you pass an object by value to the function, you incurr a copy or move-copy construction. But you are not keeping track of that with your primitive memory leak checker. You could provide your own copy constructor, and then you will see two objects are being created, and only one is being destroyed:
#include<iostream>
class MyObject
{
public:
MyObject() {std::cout << "creation of my object" << std::endl;}
MyObject(const MyObject&) {std::cout << "copy creation of my object" << std::endl;}
~MyObject() {std::cout << "destruction of my object" << std::endl;}
};
void processMyObject(MyObject foo) {}
int main()
{
processMyObject(*new MyObject());
}
Output:
creation of my object
copy creation of my object
destruction of my object
Because you're taking the MyObject by value.
Thus there is a destruction. But it is the destruction of the foo argument at the end of processMyObject.
The *new does actually still leak in this case.
EDIT: As pointed out by juanchopanza, you need to also print a statement in the copy constructor and in the move constructor as well.
What happens in your code
You construct an object and get information about it (creation of my object)
You pass it to function - copy constructor fires, but does not report anything
The copy is destroyed - you get information about it (destruction of my object)
The original instance leaks despite fact, that you don't have any information about it.
How to see it?
Simply report pointers to this during construction and destruction (quick'n'dirty, please don't complain):
class MyObject
{
public:
MyObject(){std::cout << "creation of my object (" << (int)this << ")" << std::endl;}
virtual ~MyObject(){std::cout << "destruction of my object (" << (int)this << ")" << std::endl;}
};
Result:
creation of my object (165437448)
destruction of my object (-1076708692)
As you see, destroyed object is different than created one.
How to "fix" it to show the leak?
The simplest way to "fix" your code is to pass object by pointer:
#include<iostream>
class MyObject
{
public:
MyObject(){std::cout << "creation of my object" << std::endl;}
virtual ~MyObject(){std::cout << "destruction of my object" << std::endl;}
};
void processMyObject(MyObject * foo)
{
}
int main()
{
processMyObject(new MyObject());
return 0;
}
Another option is to report copy ctors and move ctors as well:
class MyObject
{
public:
MyObject(){std::cout << "creation of my object" << std::endl;}
MyObject(const MyObject & obj) { std::cout << "copy-ctor" << std::endl; }
MyObject(MyObject && obj) { std::cout << "move-ctor" << std::endl; }
virtual ~MyObject(){std::cout << "destruction of my object" << std::endl;}
};
There actually is a memory leak. Just because your object was destroyed, doesn't mean that you deleted the resources you acquired with new. You have to explicitly use delete.
EDIT
So here's what's happening:
You are calling the default constructor on the fly, and passing it to the function call. This prints the first message.
As part of the function call, the object is passing to processMyObject(), creating a new object in that scope using the copy constructor, which has been implicitly defined by the compiler.
When that object (in processMyObject()) goes out of scope, its destructor is called, printing the second message.
So, the instance printing the first message is different from that printing the second one.
Hope that clears things up.
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
How to return member that can be changed?
I learn that if i use in const& in the assignment (and in the called method signature) than the lifetime of the refereed object is extended until end of method.
Employee const& getEmp(int a) {
return Employee(a);
}
Employee const& tmpEmp = m.getEmp(10); //
... stuff
//end of scope - tmpEmp valid until here
I wrote little program and saw that it work as expected.
My question is not how to do this?
My question is about how compiler do this?
As you see from the example the destructor is called immediately after return , so i wonder how is that the destructor called , but tmpEmp is valid after the desructor called ?
#include <iostream>
using namespace std;
class Employee {
public:
Employee() : a(0){
cout << "c-emp" << a << endl;
}
Employee(const Employee& newE) {
a = newE.a;
cout << "c-c-emp" << a << endl;
}
Employee(int a) : a(a) {
cout << "c-emp" << a << endl;
}
~Employee() {
cout << "d-emp" << a << endl;
}
int a;
};
class Manager {
public:
Manager() {}
~Manager() {}
Employee const& getEmp(int a) {
return Employee(a);
}
};
int main(int argc, char **argv) {
Manager m;
Employee const& tmpEmp = m.getEmp(10);
cout << "tmpEmp " << tmpEmp.a <<endl;
}
output:
c-emp10
d-emp10 - destructor is called and tmpEmp is still valid? how is that?
tmpEmp 10
You learned wrong.
First, assignment never has any effect on the lifetime of an object.
It's just an operator with a side effect.
Second, if you initialize (not assign) a const reference with a
temporary, the lifetime of the temporary is extended to match the
lifetime of the reference. There are exceptions, however. (And I've
never found any pratical use for this feature.)
A const reference used as a return value is one of the exceptions (for
the simple reason that it's not implementable). Initializing a return
of a const reference type with a temporary does not extend the life of
the temporary.
And finally, even if it did, it wouldn't help you in your case, because
the reference which was initialized by the temporary ceases to exist
after the full expression which invokes the function.
Your code is wrong. You are returning a reference to a local object, and the local object is not eligible for the lifetime extension you learned about. The lifetime of local objects end before you even get a chance to assign the return value to another variable, and therefore there's no way to extend their lifetime.
The lifetime extension is for temporary objects:
Employee getEmp(int a) {
return Employee(a);
}
Employee const& tmpEmp = m.getEmp(10); //
... stuff
//end of scope - tmpEmp valid until here
Now getEmp() returns a temporary object (not a reference to a local object,) and that object is still valid when the assignment occurs. So its lifetime gets extended.