The code below introduces a class C. The class has constructor, copy constructor, operator= and one member. How can I get the address of the object created by C(2) in the function main()?
#include <iostream>
class C
{
public:
int a;
C(const C &other)
{
std::cout << "Copy Constructor:" << a << std::endl;
}
C(int a)
{
this->a = a;
std::cout << "Constructor:" << a << std::endl;
}
C &operator=(const C &other)
{
std::cout << "operator=:this.a = " << a << " | other.a = " << other.a << std::endl;
a = other.a;
return *this;
}
~C()
{
std::cout << "Destructor:" << a << std::endl;
}
};
int main()
{
C a(1);
a = C(2);
}
You can't. You are forbidden from taking addresses of temporaries. They will go out of scope very quickly, leaving you with an invalid address.
You could use a helper function to write the address somewhere before the object goes out of scope:
template <typename T>
T const & store_possibly_invalid_address(T const & t, T const *& p)
{
p = &t;
return t;
}
int main()
{
C a(1);
C const * invalid_address;
a = store_possibly_invalid_address(C(2), invalid_address);
// The temporary is out of scope, but you can see where it was.
// Don't dereference the pointer.
}
That could be educational, to discover where the compiler chooses to put temporaries. It has no purpose in any real code, though.
The only way is with some collaboration inside the class; the
constructor has the address (the this pointer), and can put it
somewhere where you can get at it later. I'd recommend against it,
though, since the object won't live long enough for you to do much with
it. (On the other hand, it's sometimes useful for debugging to output
it.)
Related
I got this code:
Edit: The full code:
#include <iostream>
using namespace std;
class A {
public:
A() {}
A(const A& a) {
cout << "A copy ctor" << endl;
}
virtual ~A() {
cout << "A dtor" << endl;
}
virtual void type() const {
cout << "This is A" << endl;
}
};
class B: public A {
public:
B(){}
virtual ~B() {
cout << "B dtor" << endl;
}
void type() const override {
cout << "This is B" << endl;
}
};
A f(A a) {
a.type();
return a;
}
const A& g(const A& a) {
a.type();
return a;
}
int main() {
A* pa = new B();
cout << "applying function f:" << endl;
f(*pa).type();
cout << "applying function g:" << endl;
g(*pa).type();
delete pa;
return 0;
}
I noticed when debugging the code that after making and passing a copy of *pa to f and ending the function the destructor of the copy (*pa) that was passed to f is not called.
Only when type() ended (the same line) both the copies (I assume) were erased by the destructors
I was sure that when ending the function a destructor will be called and erase the current copy which did not happened in this case. I would like to get an explanation to the order in which the constructors and desturctors are being called in the code (I am not very knowledgeable about the order when methods are involved and I could not find much about it online).
thank you.
When you do f(*pa).type();, the Copy Constructor of A is called with an A object, so it will create an A to pass into your f function. When f returns, it is a different A being returned, since it's not by ref, however, it is NOT immediately destroyed, and instead uses copy-elision to stick around until after the .type() is called.
After that point, the destructor of both the temporary object passed into f, and the temporary object return by f are destroyed, so ~A() gets called twice.
I was developing some class and bumped for this question.
Consider I have following class:
struct A
{
int *p;
A()
{
p = new int(1);
cout << "ctor A" << endl;
}
A(const A& o)
{
cout << "copy A" << endl;
p = new int(*(o.p));
}
A(A&& o)
{
cout << "move A" << endl;
p = std::move(o.p);
o.p = NULL;
}
A& operator=(const A& other)
{
if (p != NULL)
{
delete p;
}
p = new int(*other.p);
cout << "copy= A" << endl;
return *this;
}
A& operator=(A&& other)
{
p = std::move(other.p);
other.p = NULL;
cout << "move= A" << endl;
return *this;
}
~A()
{
if(p!=NULL)
delete p;
p = NULL;
cout << "dtor A" << endl;
}
};
And following class which has A as a property:
class B {
public:
B(){}
A myList;
const A& getList() { return myList; };
};
And this function which checks for some variable value and returns different objects in different cases:
B temp;
A foo(bool f)
{
A a;
*a.p = 125;
if (f)
return a;
else
{
return temp.getList();
}
}
Now, I am want to use this function like this:
A list1 = foo(true);
if(list1.p != NULL)
cout << (*list1.p) << endl;
cout << "------"<<endl;
A list2 = foo(false);
if (list2.p != NULL)
cout << (*list2.p) << endl;
The purpose of this situation is:
Function foo should return (or move) without copying some local object with changes in p if argument is true, or should return property of global variable temp without calling copy constructors of A (i.e. return reference of myList) and also it should not grab myList from B (it should not destroy myList from B, so std::move can not be used) if argument is false.
My question is:
How should i change function foo to follow upper conditions? Current implementation of foo works right in true case and moving that local variable, but in case false it calls copy constructor for list2. Other idea was to somehow extend lifetime of local variable, but adding const reference did not work for me. Current output is:
ctor A
ctor A
move A
dtor A
125
------
ctor A
copy A
dtor A
1
dtor A
dtor A
dtor A
If you can change B to
class B {
public:
B(){}
std::shared_ptr<A> myList = std::make_shared<A>();
const std::shared_ptr<A>& getList() const { return myList; };
};
then foo can be:
B b;
std::shared_ptr<A> foo(bool cond)
{
if (cond) {
auto a = std::make_shared<A>();
*a->p = 125;
return a;
} else {
return b.getList();
}
}
Demo
Output is
ctor A
ctor A
125
------
1
dtor A
dtor A
The simplest solution is probably to use std::shared_ptr as in Jarod42's answer. But if you want to avoid smart pointers, or if you can't change B you can probably create your own wrapper class that might or might not own an A. std::optional might be quite convenient for this:
class AHolder {
private:
std::optional<A> aValue;
const A& aRef;
public:
AHolder(const A& a) : aRef(a) {}
AHolder(A&& a) : aValue(std::move(a)), aRef(aValue.value()) {}
const A* operator->() const { return &aRef; }
};
The class contains an optional to own the A if required and you can use move-semantics to move it in. The class also contains a reference (or pointer) that either references the contained value or references another object.
You can return this from foo:
AHolder foo(bool f)
{
A a;
*a.p = 125;
if (f)
return a;
else
{
return temp.getList();
}
}
And the caller can access the contained reference:
auto list1 = foo(true);
if(list1->p != nullptr)
cout << (*list1->p) << endl;
cout << "------"<<endl;
auto list2 = foo(false);
if (list2->p != nullptr)
cout << *list2->p << endl;
Live demo.
If you don't have access to std::optional there is boost::optional or you could use std::unique_ptr at the cost of a dynamic memory allocation.
Your function foo returns an instance of A, not a reference (nor a pointer), so you can`t get access to B.myList content without copying or moving.
In order to have this access you should either use smart pointers (like Jarod42 wrote) or just simple pointers like this:
B temp;
A* foo(bool f)
{
if (f)
{
A* ptr = new A;
*ptr->p = 125;
return ptr;
}
else
{
return &temp.getList();
}
}
However this particular code will not work coz .getList() returns const reference but foo returns non-const pointer (this could but should not be dirty hacked with const_cast<>).
Generally you need to choose what exactly the foo function should return:
new instance of A class with specific data
access to existing instance
If you have to make this decision on runtime (for example by your bool parameter) then the pointers (simple or smart - whatever) are the only option (also remember to delete manually allocated memory).
I have the following sample code, and the copy assignment is doing something I don't want - it's first constructing the new samp(6), then copying it to z, then destroying the new samp(6) it built. Is there a way to change the constructors such that = acts like a pointer, destroying the originally constructed samp(5) and replacing it with the new samp(6), calling the destructor on samp(5), rather than samp(6)?
#include <iostream>
class samp
{
public:
samp(int a)
{
m_a = a;
std::cout << "cons" <<m_a << std::endl;
}
int m_a;
samp(const samp& other)
{
std::cout << "copy" << m_a << std::endl;
m_a = other.m_a;
}
samp& operator= (const samp& other)
{
std::cout << "assg" << m_a << std::endl;
samp* z =new samp(other.m_a);
return *z;
}
~samp()
{
std::cout << "dest" <<m_a<< std::endl;
}
};
int main()
{
samp z(5);
z = samp(6);
std::cout << z.m_a << std::endl;
return 0;
}
Maybe pointer semantics is what you want:
#include <memory>
// ...
auto z = std::make_unique<samp>(5);
z = std::make_unique<samp>(6); // dest5
std::cout << z->m_a << '\n'; // 6
Although if you are coming to C++ from a language where object names are object references, it may be better to get used to C++ value semantics instead of trying to replicate object references :)
operator= is a member of your object so the this pointer is available. Also, assignment means the target of the assignment should change. Your version is creating a new object, but leaving the target alone. See if this does what you want:
samp& operator= (const samp& other)
{
m_a = other.m_a;
return *this;
}
lets say I have a class with 2 constructors like so:
class Foo
{
Foo(int x);
Foo();
...
}
I know that I can call one constructor from another like Foo() : Foo(42) {}, but why shouldn't (or should) I do the following:
Foo() {
Foo(42)
}
What is the difference in these cases?
Some suggest to use an "initializer" method, called from any constructor with their respective arguments, but I am puzzled as to what happens in the case above?
Let's put this example:
#include <iostream>
class B
{
private:
int number;
public:
B()
{
B(1);
}
B(int x) : number(x)
{
std::cout << "Constructor: " << x << std::endl;
}
void print(){
std::cout << "Msg: " << number << std::endl;
}
~B(){std::cout << "Destructor: " << number << std::endl;}
};
int main() {
B b;
b.print();
return 0;
}
Output:
Constructor: 1
Destructor: 1
Msg: 1
Destructor: 1
You are destroying a second object! This is strange, what happens if we use pointers...
#include <iostream>
class B
{
private:
int* arr;
public:
B()
{
B(1);
}
B(int x)
{
std::cout << "Constructor: " << x << std::endl;
arr = new int[x];
}
void print(int n){
std::cout << "Msg: " << arr[n] << std::endl;
}
void set(int n,int val){
arr[n] = val;
}
~B()
{
std::cout << "Destructor: " << arr << std::endl;
delete[] arr;
}
};
int main() {
B b;
b.set(0,14);
b.print(0);
return 0;
}
Constructor: 1
Destructor: 0xc45480
Msg: 14
Destructor: 0xc45480
Look up the pointer addr. They are the same, this means:
We are writing in deleted memory.
We are deleting the same memory twice.
These are two serious problems. You shouldn't do that.
Expression Foo(){Foo(42);} constructs anonymous temporary object that gets destroyed immediately without changing the object being constructed anyhow, while from Foo() : Foo(42){} will initialize the object being constructed.
You should not the following:
Foo() {
Foo(42)
}
When you are in the constructor body the member variables have been just constructed. That's why in C++ initialisation list exists.
The above code is semantically wrong! You are not absolutely using
delegating construction. Instead the statement Foo(42) in the body will just create another object without assigning it to any variable (anonymous variable).
You can imagine something like:
Foo() {
Foo another_obj = Foo(42);
}
In order to use delegating constructor, you must call constructor
in the initialisation list.
Foo() : Foo(42) { }
Say I have this function:
template <class A>
inline A f()
{
A const r(/* a very complex and expensive construction */);
return r;
}
Is it a good idea to declare r const, since a const variable cannot be moved? Note that the returned value is not const. The qualm I am grappling is, that r truly is const, but it may not be a good idea to declare it as such. Yet the qualifier should be helping the compiler generate better code.
As demonstrated here, NRVO elides the copy of r implied by the line return r;
#include <iostream>
struct A {
const char* name;
A( const char* name_ ):name(name_) { std::cout << "created " << name << "\n"; }
A(A const&){ std::cout << "copied " << name << "\n"; }
A(A &&){ std::cout << "moved " << name << "\n"; }
};
A f() {
std::cout << "start of f()\n";
A const r("bob");
std::cout << "body of f()\n";
return r;
}
int main() {
A x = f();
}
And the copy in main is also elided.
If you block NRVO and RVO in some other way (for instance using the flag -fno-elide-constructors when compiling with GCC), the const can cause your object to be copied instead of moved. You can see this if we remove the copy constructor from A:
#include <iostream>
struct A {
const char* name;
A( const char* name_ ):name(name_) { std::cout << "created " << name << "\n"; }
//A(A const&){ std::cout << "copied " << name << "\n"; }
A(A &&){ std::cout << "moved " << name << "\n"; }
};
A f() {
std::cout << "start of f()\n";
A const r("bob");
std::cout << "body of f()\n";
return r;
}
int main() {
A x = f();
}
the code no longer compiles. While the copy constructor isn't executed so long as NRVO occurs, its existence is required by your const local variable.
Now, NRVO requires a few things, such as a single variable which is returned along every single execution path of the function in question: if you ever "abort" and do a return A(), NRVO is blocked, and your const local variable suddenly forces a copy at all return sites.
If class A is under your control, and you want to return const objects by move, you can do
mutable bool resources_were_stolen = false;
and set that to true in a const move constructor
A(const A&& other) { ...; other.resources_were_stolen = true; }
~A() { if (!resources_were_stolen) ... }
Actually, the destructor probably would become if (resources_were_stolen) some_unique_ptr.release();, using the fact that objects lose their const-ness during construction and destruction.