How is an array that stores multiple IClass objects, into which we add instances of Class objects that implements IClass gets stored in memory? I am trying to confirm if my assumption is right (in case of 32 bit app)
we have an array of 32 bit pointers to the IClass objects that have a 32 bit pointer to the actual instance object of Class that takes up sizeof(Class) in memory? Also, if an interface doesnt have any virtual/abstract methods it only has a 32 bit pointer at its root and thats it?
Is this right?
as always, any input appreciated
edit:
say we have the following definitons:
class Class : IClass
{
int foo();
int bar;
}
class IClass
{
virtual int vfunc();
}
// array def:
IClass arr[1337];
I begin storing Class in the array arr, how does the runtime store sizeof(Class) into something that have sizeof(IClass) allocated for it?
how does the runtime store sizeof(Class) into something that have sizeof(IClass) allocated for it?
It does not. By assigning a Class instance to an element of the IClass array you are effectively invoking the IClass copy-constructor and copying just the parent part of the object. This is called "slicing", as explained in this answer.
In order to avoid it, you need to hold pointers (or references) to IClass. Three problems arise then:
You cannot copy the actual values, only move them or reference them, unless you implement a virtual "clone" method for your class hierarchy.
You need to handle ownership: an array of class C owns its instances, but an array of C* or C& does not. Normally you would want to use unique_ptr<T> or shared_ptr<T>, depending on the lifetime that is expected for the instances and who will see them.
You need a way to polymorphically construct and destroy the elements. The latter is easy, you just declare the destructor virtual at the base class. The former usually involves either somebody else passing you the instances they want saved (e.g. using an unique_ptr<IClass> that gives you the ownership) or creating some sort of factory infrastructure.
Related
I have came from those questions:
Why can't we declare a std::vector<AbstractClass>?
abstract classes in std containers
How to store a vector of objects of an abstract class which are given by std::unique_ptr?
They all suggested that I should use pointer or smart pointers instead.
As far as I know, Data are dynamically allocated in std::vector which means that there are pointers internally in the std::vector. So why I can not use abstract classes directly? why I have to use pointers(The one I specified) for pointers(the internally) in order to use abstract classes with std::vector. I know some features like std::vector::resize won't work. However, std::vector::reserve and std::back_inserter will solve the problem.
As far as I know, Data are dynamically allocated in std::vector which means that there is pointers internally in the std::vector
That's absolutely right. However, the pointer (actually, one of two pointers in the very common implementation) points to an array of identically-sized elements of type T, not to a single element of T or its subtype. Essentially, the pointer is used to represent an array, not to refer to a class or its subclass.
That is why you need an extra level of indirection - elements of an array T[] are not capable of storing subclasses of T without object slicing.
Data are dynamically allocated in std::vector which means that there is pointers internally in the std::vector
No, that's a misconception. std::vector allocates an array of instances internally, and you can't create an instance of an abstract class.
While it is true that memory for std::vector is allocated dynamically, the fact is that in std::vector<T> objects of type T are stored as copies. And you simply cannot copy abstract classes.
For example, if you have a base class A, a derived class B, and a std::vector<A>. Then, if you try to stored an object of type B in that vector, it will be copied and stored as an A. That is, it will be spliced.
class A {};
class B: public A {};
int main()
{
std::vector<A> as;
B b;
as.push_back(b); //<-- splice!!!
}
That, assuming that class A is copiable (and non-abstract). If it is abstract the compiler will save you the trouble and fail the declaration of the vector.
In order to insert something into a vector, the template has to first instantiate the class (since it uses the copy constructor). Since this is not possible with an abstract class, you can't do it!
Source
I am wondering why I cannot initialize an array of abstract objects to the stack but not the heap.
Here is some C++ code similar to mine that fails on the last line. I'm mainly just curious with the reasons behind this problem dealing with the heap vs. the stack. Thanks in advance!
#define ARRAY_SIZE 10
class Obj {
public:
virtual void fn() =0;
};
class Sub : public Obj {
public:
void fn() {
// ...
}
};
Obj * o1_array[ARRAY_SIZE];
Obj * o2_array = new Obj[ARRAY_SIZE]; // Compiler Error
You are doing two very different things. In the "stack" case,
Obj * o1_array[ARRAY_SIZE];
you are initializing an array of pointers. You don't need a complete or non-abstract type for this. In the "heap" case,
Obj * o2_array = new Obj[ARRAY_SIZE];
you are initializing an array of objects on the RHS and assigning the address of the first element to a pointer in the LHS. You need a complete, non-abstract type to build the array. If you want a dynamically-sized collection of pointers, a good bet is to use a container of pointers (assuming something else takes care of the management of the pointees' lifetime) or a container of smart pointers (where the smartness of the pointer decides who manages the pointee).
Non-managing:
std::vector<Obj*> o1_array(ARRAY_SIZE);
Managing (unique ownership):
std::vector<std::unique_ptr<Obj>> o1_array(ARRAY_SIZE);
For more options on containers managing "pointers", see the boost pointer container library.
This is one topic that is not making sense to me. Pointers to data members of a class can be declared and used. However,
What is the logic that supports the idea ? [I am not talking about the syntax, but the logic of this feature]
Also,if i understand this correctly, this would imply an indefinite/variable amount of memory being allocated at the pointer initialization as any number of objects may exist at that time. Also, new objects may be created and destroyed during runtime. Hence, in effect, a single statement will cause a large number of allocations/deallocations. This seems rather counter-intuitive as compared to the rest of the language. Or is my understanding of this incorrect ? I dont think there is any other single initialization statement that will implicitly affect program execution as widely as this.
Lastly, how is memory allocated to these pointers ? Where are they placed with respect to objects ? Is it possible to see physical memory addresses of these pointers ?
A single declaration of a pointer to a data member, creates pointers for every object of that class.
No, it does not. A pointer to a member is a special object that is very different from a pointer; it is a lot more similar to an offset. Given a pointer to an object of the class and a member pointer, you'd be able to get the value of a member; without the pointer to an object of a class a pointer to a member is useless.
Questions 2 and 3 stem from the same basic misunderstanding.
A single declaration of a pointer to a data member, creates pointers for every object of that class.
No. It creates a pointer to a member (which can be though of as an offset from the base of object)
You can then use it with a pointer to an object to get that member.
struct S
{
int x;
int y;
};
int S::* ptrToMember = &S::x; // Pointer to a member.
S obj;
int* ptrToData = &obj.x; // Pointer to object
// that happens to be a member
Notice in creating the pointer to a member we don't use an object (we just use the type information). So this pointer is an offset into the class to get a specific member.
You can access the data member via a pointer or object.
(obj.*ptrToMember) = 5; // Assign via pointer to member (requires an object)
*ptrToData = 6; // Assign via pointer already points at object.
Why does this happen as opposed to a single pointer being created to point to only one specific instance of the class ?
That is called a pointer.
A similar but parallel concept (see above).
What is the logic that supports the idea ?
Silly example:
void addOneToMember(S& obj, int S::* member) { (obj.*member) += 1; }
void addOneToX(S& obj) { addOneToMember(obj, &Obj::x);}
void addOneToY(S& obj) { addOneToMember(obj, &Obj::y);}
Also,if i understand this correctly, this would imply an indefinite/variable amount of memory being allocated at the pointer initialization as any number of objects may exist at that time.
No. Because a pointer to a member is just an offset into an object. You still need the actual object to get the value.
Lastly, how is memory allocated to these pointers ?
Same way as other objects. There is nothing special about them in terms of layout.
But the actual layout is implementation defined. So there is no way of answering this question without referring to the compiler. But it is really of no use to you.
Is it possible to see physical memory addresses of these pointers ?
Sure. They are just like other objects.
// Not that this will provide anything meaningful.
std::cout.write(reinterpret_cast<char*>(&ptrToMember), sizeof(ptrToMember));
// 1) take the address of the pointer to member.
// 2) cast to char* as required by write.
// 3) pass the size of the pointer to member
// and you should write the values printed out.
// Note the values may be non printable but I am sure you can work with that
// Also note the meaning is not useful to you as it is compiler dependent.
Internally, for a class that does not have virtual bases, a pointer-to-member-data just has to hold the offset of the data member from the start of an object of that type. With virtual bases it's a bit more complicated, because the location of the virtual base can change, depending on the type of the most-derived object. Regardless, there's a small amount of data involved, and when you dereference the pointer-to-data-member the compiler generates appropriate code to access it.
If I have several levels of object containment (one object defines and instantiates another object which define and instantiate another object..), is it possible to get access to upper, containing - object variables and functions, please?
Example:
class CObjectOne
{
public:
CObjectOne::CObjectOne() { Create(); };
void Create();
std::vector<ObjectTwo>vObejctsTwo;
int nVariableOne;
}
bool CObjectOne::Create()
{
CObjectTwo ObjectTwo(this);
vObjectsTwo.push_back(ObjectTwo);
}
class CObjectTwo
{
public:
CObjectTwo::CObjectTwo(CObjectOne* pObject)
{
pObjectOne = pObject;
Create();
};
void Create();
CObjectOne* GetObjectOne(){return pObjectOne;};
std::vector<CObjectTrhee>vObjectsTrhee;
CObjectOne* pObjectOne;
int nVariableTwo;
}
bool CObjectTwo::Create()
{
CObjectThree ObjectThree(this);
vObjectsThree.push_back(ObjectThree);
}
class CObjectThree
{
public:
CObjectThree::CObjectThree(CObjectTwo* pObject)
{
pObjectTwo = pObject;
Create();
};
void Create();
CObjectTwo* GetObjectTwo(){return pObjectTwo;};
std::vector<CObjectsFour>vObjectsFour;
CObjectTwo* pObjectTwo;
int nVariableThree;
}
bool CObjectThree::Create()
{
CObjectFour ObjectFour(this);
vObjectsFour.push_back(ObjectFour);
}
main()
{
CObjectOne myObject1;
}
Say, that from within CObjectThree I need to access nVariableOne in CObjectOne. I would like to do it as follows:
int nValue = vObjectThree[index].GetObjectTwo()->GetObjectOne()->nVariable1;
However, after compiling and running my application, I get Memory Access Violation error.
What is wrong with the code above(it is example, and might contain spelling mistakes)?
Do I have to create the objects dynamically instead of statically?
Is there any other way how to achieve variables stored in containing objects from withing contained objects?
When you pass a pointer that points back to the container object, this pointer is sometimes called a back pointer. I see this technique being used all the time in GUI libraries where a widget might want access to its parent widget.
That being said, you should ask yourself if there's a better design that doesn't involve circular dependencies (circular in the sense that the container depends on the containee and the containee depends on the container).
You don't strictly have to create the objects dynamically for the back pointer technique to work. You can always take the address of a stack-allocated (or statically-allocated) object. As long as the life of that object persists while others are using pointers to it. But in practice, this technique is usually used with dynamically-created objects.
Note that you might also be able to use a back-reference instead of a back-pointer.
I think I know what's causing your segmentation faults. When your vectors reallocate their memory (as the result of growing to a larger size), the addresses of the old vector elements become invalid. But the children (and grand-children) of these objects still hold the old addresses in their back-pointers!
For the back-pointer thing to work, you'll have to allocate each object dynamically and store their pointers in the vectors. This will make memory management a lot more messy, so you might want to use smart pointers or boost::ptr_containers.
After seeing the comment you made in another answer, I now have a better idea of what you're trying to accomplish. You should research generic tree structures and the composite pattern. The composite pattern is usually what's used in the widget example I cited previously.
Maybe all your object can inherit from a common interface like :
class MyObject
{
public:
virtual int getData() = 0;
}
And after you can use a std::tree from the stl library to build your structure.
As Emile said, segmentation fault is caused by reallocation. Exactly speaking -- when the local stack objects' 'this' pointer was passed to create another object, which is then copied to the vector container. Then the 'Create()' function exits, the stack frame object ceases to exist and the pointer in the container gets invalid.
Let's say we have a class that looks like this:
class A
{
public:
int FuncA( int x );
int FuncB( int y );
int a;
int b;
};
Now, I know that objects of this class will be laid out in memory with just the two ints. That is, if I make a vector of instances of class A, there will be two ints for one instance, then followed by two ints for the second instance etc. The objects are POD.
BUT let's say the class looks like this:
class B
{
public:
int FuncA( int x );
int FuncB( int y );
};
What do objects of this class look like in memory? If I fill a vector with instances of B... what's in the vector? I've been told that non-virtual member functions are in the end compiled as free functions somewhere completely unrelated to the instances of the class in which they're declared (virtual function are too, but the objects store a vtable with function pointers). That the access restrictions are merely at the semantic, "human" level. Only the data members of a class (and the vtable etc.) actually make up the memory structure of objects.
So again, what do objects of class B look like in memory? Is it some kind of placeholder value? Something has to be there, I can take the object's address. It has to point to something. Whatever it is, is the compiler allowed to inline/optimize out these objects and treat the method calls as just normal free function calls? If I create a vector of these and call the same method on every object, can the compiler eliminate the vector and replace it with just a bunch of normal calls?
I'm just curious.
All objects in C++ are guaranteed to have a sizeof >= 1 so that each object will have a unique address.
I haven't tried it, but I would guess that in your example, the compiler would allocate but not initialize 1 byte for each function object in the array/vector.
As Ferruccio said, All objects in C++ are guaranteed to have a size of at least 1. Mostly likely, it's 1 byte, but fills out the size of the alignment, but whatever.
However, when used as a base class, it does not need to fill any space, so that:
class A {} a; // a is 1 byte.
class B {} b; // b is 1 byte.
class C { A a; B b;} c; // c is 2 bytes.
class D : public A, B { } d; // d is 1 byte.
class E : public A, B { char ee; } e; // e is only 1 byte
What do objects of this class look like in memory?
It's entirely up to the compiler. An instance of an empty class must have non-zero size, so that distinct objects have distinct addresses (unless it's instantiated as a base class of another class, in which case it can take up no space at all). Typically, it will consist of a single uninitialised byte.
Whatever it is, is the compiler allowed to inline/optimize out these objects and treat the method calls as just normal free function calls?
Yes; the compiler doesn't have to create the object unless you do something like taking its address. Empty function objects are used quite a lot in the Standard Library, so it's important that they don't introduce any unnecessary overhead.
I performed the following experiment:
#include <iostream>
class B
{
public:
int FuncA( int x );
int FuncB( int y );
};
int main()
{
std::cout << sizeof( B ) ;
}
The result was 1 (VC++ 2010)
It seems to me that the class actually requires no memory whatsoever, but that an object cannot be zero sized since that would make no semantic sense if you took its address for example. This is borne out by Ferruccio's answer.s
Everything I say from here on out is implementation dependent - but most implementations will conform.
If the class has any virtual methods, there will be an invisible vtable pointer member. That isn't the case with your example however.
Yes, the compiler will treat a member function call the same as a free function call, again unless it's a virtual function. Even if it is a virtual function, the compiler can bypass the vtable if it knows the concrete type at the time of the call. Each call will still depend on the object, because there's an invisible this parameter with the object's pointer that gets added to the call.
I would think they just look like any objects in C++:
Each instance of the class occupies space. Because objects in C++ must have a size of at least 1 (so they have unique addresses, as Ferruccino said), objects that don't specify any data don't receive special treatment.
Non-virtual functions do not occupy any space at all in a class. Rather, they can be thought of as functions like this:
int B_FuncA(B *this, int x);
int B_FuncB(B *this, int y);
If this class can be used by other .cpp files, I think these will become actual class instances, not regular functions.
If you just want your functions to be free rather than bound to objects, you could either make them static or use a namespace.
I've been told that non-virtual member functions are in the end compiled as free functions somewhere completely unrelated to the instances of the class in which they're declared (virtual function are too, but the objects store a vtable with function pointers). That the access restrictions are merely at the semantic, "human" level. Only the data members of a class (and the vtable etc.) actually make up the memory structure of objects.
Yep, that is usually how it works. It might be worth pointing out the distinction that this isn't specified in the standard, and it's not required -- it just makes sense to implement classes like this in the compiler.
So again, what do objects of class B look like in memory? Is it some kind of placeholder value? Something has to be there, I can take the object's address
Exactly. :)
The C++ standard requires that objects take up at least one byte, for exactly the reason you say. It must have an address, and if I put these objects into an array, I must be able to increment a pointer in order to get "the next" object, so every object must have a unique address and take up at least 1 byte. (Of course, empty objects don't have to take exactly 1 byte. Some compilers may choose to make them 4 bytes, or any other size, for performance reasons)
A sensible compiler won't even make it a placeholder value though. Why bother writing any specific value into this one byte? We can just let it contain whatever garbage it held when the object was created. It'll never be accessed anyway. A single byte is just allocated, and never read or written to.