I have asked this question. My question now is how this works? To elaborate, how can I point to an object that is not yet initialised. I have made this MWE and it shows that the object is copy created not copy assigned .i.e. the object is not yet initialised yet I am able to point to it.
#include <iostream>
class Foo {
public:
int x;
Foo(const Foo& ori_foo) {
std::cout << "constructor" << std::endl;
x = ori_foo.x;
}
Foo& operator = (const Foo& ori_foo) {
std::cout << "operator =" << std::endl;
x = ori_foo.x;
return *this;
}
Foo(int new_x) {
x = new_x;
}
};
class BarParent {
public:
Foo *p_foo;
BarParent(Foo* new_p_foo) : p_foo(new_p_foo)
{
std::cout << (*new_p_foo).x << std::endl;
}
};
class BarChild : public BarParent {
public:
Foo foo;
BarChild(Foo new_foo)
:BarParent(&foo) //pointer to member not yet initialised
,foo(new_foo) // order of initilization POINT OF INTEREST
{}
};
int main() {
Foo foo(101);
BarChild bar(foo);
std::cout << bar.p_foo->x << std::endl;
std::cout << bar.foo.x << std::endl;
}
Output:
constructor
0
constructor
101
101
Do not be afraid of getting into details of how the memory is handled. And, where every member resides.
Don't mistake Initialization for Allocation. BarChild::foo will be allocated before the constructor is called since it is stored in place, so there will be a well defined location for BarParent::p_foo to point at. Foo's constructor will Initialize BarChild::foo, but as long as you don't try to read from BarChild::foo before the constructor is called you will not notice the ordering.
At this line
BarChild bar(foo);
the compiler reserves enough stack space for a BarChild object then calls the constructor to begin the object's lifetime. Within the object the foo member has a fixed offset, every BarChild object has a foo member at the same offset within it, so since the this pointer has a known address within the constructor (it's the address of bar on the stack) then this->foo is also at a known address, even if the memory at that address hasn't been initialized yet. The BarChild obejct doesn't "grow bigger" as each member is initialized, its size is fixed and space for all the members is already "reserved" before they're initialized.
This is somewhat analogous to:
char raw_memory[sizeof(Foo)]; // define block of uninitialized memory
char* addr = raw_memory; // take address of uninitialized memory
new (raw_memory) Foo; // initialize memory
The object doesn't exist yet, and it's not valid to use it, but its address is known in advance of it being initialized.
Related
Say there is an object with automatic storage duration, and that object is copy-initialized from within a nested scope, like a loop body. Is the lifetime of the values created from within the nested scope extended into the containing scope?
#include<iostream>
using namespace std;
class Thing {
public:
int data;
Thing(int data) : data(data) { cout << "making a thing" << endl; }
~Thing() { cout << "destroying a thing" << endl; }
};
int main() {
Thing t = Thing(-1);
for (int i = 0; i < 4; i++) {
t = Thing(i); // this is both created AND destroyed from within this scope...?
}
cout << t.data << endl; // undefined behavior?
}
Right now, accessing t.data at the end works, but I see that the destructor for each Thing is invoked once per loop iteration, so I might just be getting lucky?
This looks relevant (but I am not a lawyer so it's tough to decipher): some 2011 c++ standard
specifically:
For such an object [with automatic storage duration] that does not have a variable length array type, its lifetime extends from entry into the block with which it is associated until execution of that block ends in any way...
So if my code snippet is undefined behavior - for a loop body to change a local variable, that local variable should be manually heap allocated and later manually released, or...?
This is perfectly legal, defined behavior.
Your mistake is in thinking that the lifetime of the Thing created inside the block matters. It doesn't. After the copy, the copy-assigned t hasn't changed what it is; it's still the same t created outside the block, it just had its values updated. Its lifetime is entirely unaffected. In the context of your quote, the "block with which it[t] is associated" is the top-level function scope (where it was declared), not the block in which it was copy-assigned.
The Thing created inside the block does expire each time, but that's fine; it was copied from, then never used again.
There is no undefined behavior here:
#include<iostream>
class Thing {
public:
int data;
Thing(int data) : data(data) { std::cout << "making a thing" << data << std::endl; }
~Thing() { std::cout << "destroying a thing" << data << std::endl; }
Thing& operator=(const Thing &t) { data = t.data; std::cout << "operator=" << std::endl; return *this; }
};
int main() {
Thing t = Thing(-1); // create object t
for (int i = 0; i < 4; i++) {
t = Thing(i);
// 1. create an object Thing(i)
// 2. use operator= to copy that object into the object t
// 3. Thing(i) object gets destroyed at the end of scope
}
// object t is still valid, but it was modified in the loop with operator=
cout << t.data << endl; // no undefined behavior here
}
You can add copy-assignment operator (operator=) member function into the Thing class to check this. In your case this operator was implicitly added by the compiler, according to the rules in the standard:
If no user-defined copy assignment operators are provided for a class
type (struct, class, or union), the compiler will always declare one
as an inline public member of the class. This implicitly-declared copy
assignment operator has the form T& T::operator=(const T&) if all of
the following is true:
each direct base B of T has a copy assignment operator whose
parameters are B or const B& or const volatile B&
each non-static data
member M of T of class type or array of class type has a copy
assignment operator whose parameters are M or const M& or const
volatile M&
If I return a vector from a function, the object to which it is assigned will have the same address (without returning it as a reference) as the one declared in the function. For example:
vector<int> f() {
vector<int> foo(5);
cout << &foo << endl;
return foo;
}
int main() {
vector<int> bar = f();
cout << &bar << endl; // == &foo
return 0;
}
Then I assumed that this is happening because of the copy constructor and the & operator may be overloaded in a way such that it prints the address of a specific member of the vector class which was copied from foo to bar.
But, if I change the scenario and move f() inside a class, the behaviour would be as I initially expected: &foo != &bar:
class A {
vector<int> foo;
public:
vector<int> f() {
foo.push_back(10);
cout << &foo << endl;
return foo;
}
};
int main() {
A a;
vector<int> bar = a.f();
cout << &bar << endl; // != &foo
return 0;
}
Can you explain what happens?
What does the address of a vector represent?
Computer memory can be thought of an array of bytes. Memory address is an index to that figurative array. This is the same for all objects, including vectors.
If I return a vector from a function, the object to which it is assigned will have the same address (without returning it as a reference) as the one declared in the function.
This is not guaranteed by the standard. But it is indeed possible. It will happen whenever Named Return Value Optimisation is used to elide the copy/move of the return value.
Then I assumed that this is happening because of the ... & operator may be overloaded in a way such that ...
The addressof operator of vector is not overloaded.
Can you explain what happens?
You return a copy of a member rather than a local automatic variable. NRVO cannot be used in this case.
Disregarding subobjects, more than one object cannot overlap the same memory at any given time. If two objects exist simultaneously, then they each must have a distinct address. On the other hand, once the memory of one object is released, it can be reused by another object.
In the first example, the lifetime of the local variable ends, so there is no problem for its memory to overlap with the memory of the variable that is initialised from the return value.
In the second example, the lifetime of a and thus also its member overlaps with the lifetime of bar, and therefore they cannot overlap in memory.
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 am a beginner in programming and I am learning about copy constructors. From different sources I can see that copy constructors are useful if I want to "deep copy" a class object so the new object's pointer members will point to new memory locations.
My question is, what is the advantage of defining the copy constructor as I do in class CopyCat in my example, if I get the same result with an empty copy constructor (as in class EmptyCat)?
My second question is, why do class Cat and class EmptyCat work differently? The only difference between them is that I define an empty copy constructor in EmptyCat. But as I run the program I can see that in EmptyCat after the copying the pointer member points to a new location while in class Cat it works as a shallow copy.
#include "iostream"
class Cat
{
public:
void GetMem() { std::cout << itsAge << "\n"; }
private:
int * itsAge = new int;
};
class EmptyCat
{
public:
EmptyCat() {}
~EmptyCat() {}
EmptyCat(EmptyCat&obj) {}
void GetMem() { std::cout << itsAge << "\n"; }
private:
int * itsAge = new int;
};
class CopyCat
{
public:
CopyCat() {}
~CopyCat() {}
CopyCat(CopyCat&obj);
int GetAge() { return *itsAge; }
void GetMem() { std::cout << itsAge << "\n"; }
private:
int * itsAge = new int;
};
CopyCat::CopyCat(CopyCat & obj)
{
itsAge = new int;
*itsAge = obj.GetAge();
}
int main()
{
Cat Garfield;
Cat Kitty(Garfield);
std::cout << "Memory addresses for the objects' <itsAge> member:" << std::endl;
std::cout << "Garfield and Kitty (Class Cat):" << std::endl;
Garfield.GetMem();
Kitty.GetMem();
EmptyCat Meow;
EmptyCat Purr(Meow);
std::cout << std::endl << "Meow and Purr (Class EmptyCat):" << std::endl;
Meow.GetMem();
Purr.GetMem();
CopyCat Fluffy;
CopyCat Felix(Fluffy);
std::cout << std::endl << "Fluffy and Felix (Class CopyCat):" << std::endl;
Fluffy.GetMem();
Felix.GetMem();
system("pause");
return 0;
}
If I run the program I get this:
Memory addresses for the objects' <itsAge> member:
Garfield and Kitty (Class Cat):
00BBDA60
00BBDA60
Meow and Purr (Class EmptyCat):
00BB46A0
00BB8280
Fluffy and Felix (Class CopyCat):
00BB82B0
00BBE8A0
Press any key to continue . . .
Deep copying and shallow copying is rather a C concept, where you have only structures and raw pointers. A pointer can be owned, in which case the copy must be deep, or it can be shared, in which case the copy is shallow (and you have to be careful about freeing it if it's allocated with malloc).
In C++, new is now effectively deprecated. We have unique pointers, which are "owning pointers" and "shared pointers". However pointers are relatively rare. Array members of classes are std::vectors, string members are std::strings. And copies are automatically deep, (You use a reference if you want a shallow copy).
Pointers are held back for relatively unusual situations, like trees and graphs.
My question is, what is the advantage of defining the copy constructor as I do in class CopyCat in my example, if I get the same result with an empty copy constructor (as in class EmptyCat)?
You don't get the same result. CopyCat allocates new memory and copies the value from the old class. The EmptyCat just allocates new memory, but does not copy the value.
My second question is, why do class Cat and class EmptyCat work differently? The only difference between them is that I define an empty copy constructor in EmptyCat. But as I run the program I can see that in EmptyCat after the copying the pointer member points to a new location while in class Cat it works as a shallow copy.
In Cat you haven't declared a copy constructor, so the compiler will generate one when needed. The default copy constructor does a member-wise copy from the original. In your case, this will copy the pointer (so that it stores the same address as the original).
In the EmptyCat you have a user defined copy constructor. But as that one doesn't handle the pointer member, its default value will be used.
int * itsAge = new int;
This is what allocates a new int and gets you a different pointer value.
You are not getting the same behavior with and without an empty copy constructor. EmptyCat(EmptyCat& obj) { } does absolutely nothing.
CopyCat(CopyCat& obj) {
itsAge = new int;
*itsAge = obj.GetAge();
}
dynamically allocates a new int and assigns to it a value from the obj.
In certain embedded situations, memory needs to be moved with memcopy style functions (such as from external memory, or using closed API calls).
When such a C++ object needs to be moved this way, however it doesn't have a default constructor, you can't do something like this, :
class Object {
//local data
public:
Object(/* not a default constructor */){}
}
//elsewhere:
Object o; //compiler will complain here...
memcpy_like_function(src_address, &o, sizeof(o));
because Object doesn't have a default constructor, and thus the compiler will complain about creating Object o.
Some notes from things that have shown up in the comments:
memcpy_like_function is like memcpy, it isn't actually memcpy. The src_address isn't a pointer to an address I can reach, or an int representing a pointer to an address I can reach. It is an int representing an address in a memory space I can't reach. The only way for me to access this memory space is with this function.
Object doesn't have a default constructor, has no virtual functions, is neither inherited from, nor inherits anything. Object is trivially copyable.
What is the correct way to deal with creating such an object in this situation, without putting it on the heap? Preferably, I would like to get a stack allocated object that will behave correctly with scope and destructors. For the purposes of this question, Object is not inheriting from anything.
This seems like a horribly bad idea, but assuming that your memcpy_like_function actually works, then you can just add a constructor to Object
class Object {
//local data
public:
Object(void* src_address)
{
memcpy_like_function(src_address, this, sizeof(*this));
}
};
//elsewhere:
Object o(src_address);
because Object doesn't have a default constructor
When Object doesn't have a default constructor,
//Object o;//NG
there is no way to construct Object unless call another ctor or factory function. Because of that, you cannot call memcpy-like function.
When you have way to construct Object, to use memcpy-like function, Object class must grantee that it is trivially copyable class and standard-layout class(not equal to POD class).
trivial class : trivially copyable class && has no default user-defined constructor
POD class : trivial class && standard-layout class
You cannot safely copy an object using a memcpy-like function unless the object is a POD type. If the object is a POD type, you should be able to use:
char destination[sizeof(Object)];
memcpy_like_function(src_address, destination, sizeof(destination));
Object* ptr = reinterpret_cast<Object*>(destination);
My gut-feel says that that should work under all compilers for POD types. Whether it is cause for undefined behavior under some rules of the standard, I am not sure.
If that is cause for undefined behavior under some rules of the standard, you won't be able to save a POD-type to a binary file and read it from the binary file in a standards compliant manner. They rely on the bit-pattern written to a file and read from a file to represent the object.
The following program produces the expected result under g++.
#include <iostream>
#include <cstring>
struct Object
{
int i;
double d;
Object(int ii, double dd) : i(ii), d(dd) {}
};
int main()
{
Object o1(10, 20.34);
char dest[sizeof(Object)];
memcpy(dest, &o1, sizeof(dest));
Object* ptr = reinterpret_cast<Object*>(dest);
std::cout << o1.i << ", " << o1.d << std::endl;
std::cout << ptr->i << ", " << ptr->d << std::endl;
}
Update, in response to OP's comments
The following program works as expected under g++.
#include <iostream>
#include <cstring>
struct Object
{
int i;
double d;
Object(int ii, double dd) : i(ii), d(dd) {}
};
Object testFunction(Object o1)
{
char dest[sizeof(Object)];
memcpy(dest, &o1, sizeof(dest));
Object* ptr = reinterpret_cast<Object*>(dest);
return *ptr;
}
int main()
{
Object o1(10, 20.34);
Object o2 = testFunction(o1);
std::cout << o1.i << ", " << o1.d << std::endl;
std::cout << o2.i << ", " << o2.d << std::endl;
o2.i = 25;
o2.d = 39.65;
std::cout << o2.i << ", " << o2.d << std::endl;
}
What you could do is simply use an array of bytes, then cast.
Note: what you are doing is not really good C++ practice, typically you should use assignment operators or copy constructors, and you should stick to the safer C++ casts rather than a brute-force C-style cast.
Anyway, that being said, this code will work:
class Object {
int i;
public:
Object(int i) : i(i) {}
void foo() const {
std::cout << i << std::endl;
}
};
void bla() {
Object one(1);
char *bytes = new char[sizeof(Object)];
memcpy(bytes, &one, sizeof(Object));
Object &anotherOne = (Object &) *bytes;
anotherOne.foo();
const Object &oneMore = (Object) *bytes;
oneMore.foo();
Object *oneMoreTime = (Object *) bytes;
oneMoreTime->foo();
delete[] bytes;
}
The output is:
1
1
1
In summary, you need to allocate a region of memory on the stack or the heap that will become the Object instance.