I'm studying the C++ class method pointers and I've crossed this example:
class A
{
public:
A();
void sample() { ...method_stuff... }
void (A::*ptrToSample);
};
A::A()
{
ptrToSample = &A::sample;
}
Now, if I've understood correctly, sample is non-static, which means that I can't invoke it without an object of A, more precisely, if I do not create an object of A, also all its non-static methods and members aren't stored in memory either.
Having said so, I get confused by the object constructor reported by the example. Shouldn't any object of A have a copy of sample? If yes, then why I have to use the & operator on the class scope instead of this operator?
Shouldn't the constructor be something like:
{
ptrToSample = &(this->sample);
}
?
Since the method is non-virtual, it shouldn't be saved in the virtual method table (right?), then where the heck is it stored? What am I missing?
Thanks for the help !
First, void (A::*ptrToSample); must be void (A::*ptrToSample)();.
sample is non-static, which means that I can't invoke it without an object of A
Yes.
more precisely, if I do not create an object of A, also all its non-static methods and members aren't stored in memory either
No, methods aren't stored in objects. There's always a single "instance" of each method in memory, and it isn't copied when you create objects. Under the hood, methods work like regular (free) functions, but with an implicit this parameter.
Shouldn't the constructor be something like: ptrToSample = &(this->sample);
It's hard to say why a specific syntax was choosen, but &(this->sample) would be somewhat misleading, since a member pointer doesn't contain a pointer to a specific object instance (so this would be discarded). You don't have to have an object to create a member pointer. The object needs to be provided later, when you dereference the pointer.
Related
#include <iostream>
struct something{
int i;
something(int i) : i(i) {}
};
class otherthing {
otherthing(){}
static something foo(int value)
{
return { value };
}
};
In this example what the foo function returns? Am I understand correctly that it creates an object on the heap and returns a pointer? Is this considered bad style? Or is it ok for structs and not classes?
I can feel that it might be a stupid question but I tried to google it and I could not find the answer. I apologize in advance if this is dumb.
In this example what the foo function returns?
Object of type something, initialized with value value.
Am I understand correctly that it creates an object on the heap and returns a pointer?
No. It creates an object with automatic lifetime (typically associated with stack memory). It returns that object and no pointer.
Is this considered bad style?
It's quite useless in this example, but in general this approach is called factory pattern. It allows you to separate creation of object from other logic, and that would be good style actually.
Or is it ok for structs and not classes?
The only difference between struct and class in C++ is the default access modifier. In struct member are by default public, in class members are by default private.
Am I understand correctly that it creates an object on the heap and returns a pointer?
No, it does not return a pointer, it returns an instance of something with automatic storage duration (which is commonly allocated on the stack) which for the return will utilize copy elision
Or is it ok for structs and not classes?
A struct and a class only differ in the default access modifier, besides that there is no difference.
In C++ (unlike C#) classes and structs are identical but for one tiny detail: the default access level for a class is private; for a struct it's public.
In your example, a something object is created on the stack in foo. When foo is called, e.g.
something s = otherthing.foo();
then the object is copied into s on the stack.
No pointers are involved.
Let's say there's a simple class hierarchy, and a state object that uses the derived class;
struct base_class {
int Value;
base_class() { this->Value = 1; }
virtual void Func() { printf("Base\n"); };
};
struct derived_class : base_class {
int Value;
derived_class() { this->Value = 2; }
void Func() { printf("Derived\n"); }
};
struct state {
int a,b,c;
derived_class Object;
};
Now, let's assume that there's an allocator, that is not aware of the types and just returns 0-initialized allocated block memory of required size.
state *State = (state *)Allocate(sizeof(state));
And now, to properly initialize the vtable pointers we must construct the object.
I've seen it done with placement new operator. And it does indeed seem to work.
However, I'm interested why if I construct the state object like this
*State = {};
The State is initialized perfectly, I see the values set to 1 and 2. But the _vfprt is 0. Even if I step into the constructor, the this pointer seems to have everything correctly set up, _vfprt points to the correct method and all.
But when I return from the constructor, the _vfprt fails to get copied itho the State object. Everything else is there. But the _vfprt is 0;
So I'm just wondering if there's a special magical copy constructor that's invoked whenever new() operator is used. And if there is one, how can I use it.
I use this kind of initialization everywhere in my app, and honestly adding placement new everywhere just to support one small class is a pain in the butt. the {} call is much cleaner (and shorter), and it makes the allocation calls so much easier. If it's not possible to make this work, I'm ok with that. I'm just confused as to why the vtable pointer is not copied back after we return from the constructor.
If anyone could explain why this happens, that would be great.
Thanks!
*state = {} is an assignment, not a construction. An assignment cannot change the dynamic type1 on an object. The virtual pointer only depends on the dynamic type of the object. So it is not necessary to copy the virtual pointer in an assignment.
In an assignment, the object on the left side is supposed to be within its life time. The placement new expression starts an object's life time, an assignment does not. In the assignment *state = {}, the compiler assumes that an object already exists at the memory location pointed to by state. So the compiler assumes that the virtual pointer has already been initialized. The placement new will construct the object, which initializes the virtual pointer.
1 The type of the most derived object, here it is state.
You invoke undefined behaviour! What you do by this assignment (*State = { };) is equivalent to: (*State).operator=({ });. As you notice, you call a function at an object of which the lifetime never began (just the same as if you did (*state).someFunction();), as no constructor ever was successfully called (well, wasn't called at all).
Peeking a bit under the hoods:
As your object is polymorphic, it receives a pointer to a virtual function table. Once an object is constructed, though, that pointer for sure won't change any more (objects cannot change their type as long as they live). So an assignment operator wouldn't need to change it! So the pointer to the vtable only gets installed inside the constructor, but as you never called one, it won't get installed at all.
This will apply for both the class itself (in given case without vtable, though) as well as for members or base classes (for all of which the assignment operators, which get called recursively, suffer from the same problem).
Say I have a pool that allocates some buffer.
int size = 10;
T* buffer = (T*) new char[size * sizeof(T)];
If I now want to assign some data to the buffer, i do the following.
buffer[0] = data;
My question is now what is the difference in initialization of objects that have vtable and those that don't.
From what I can see, I can without a problem assign classes to this buffer, and as long as I don't call any virtual functions, function calls work just fine.
e.g.
class A{
void function(){}
};
A a;
buffer[0] = a;
a.function(); // works
But:
class B{
void function(){}
virtual void virtual_function(){}
};
B b;
buffer[0] = b;
b.function(); // does work
b.virtual_function() // does not work.
Why does non-virtual function work?
Is it because the function is statically declared due to it being a normal class function and therefore is being copied when we do the assignment?
But then it doesn't make sense that I need to call the constructor on the buffer I created in case I need to make sure the virtual function works as well. new (buffer[0]) T(); in order to call the constructor on the object created.
Both examples first create the appropriate size of the buffer then do a assignment, view this as a pool where I pre-allocate memory depending on the amount of objects I want to fit in the pool.
Maybe I just looked at this to long and confused my self :)
Your non-virtual functions "work" (a relative term) because they need no vtable lookup. Under the hood is implementation-dependent, but consider what is needed to execute a non-virtual member.
You need a function pointer, and a this. The latter is obvious, but where does the fn-ptr come from? its just a plain function call (expecting a this, then any supplied arguments). There is no polymorphic potential here. No vtable lookup required means the compiler can (and often does) simply take the address of what we think is an object, push it, push any supplied args, and invoke the member function as a plain-old-call. The compiler knows which function to call, and needs no vtable-intermediary.
It is not uncommon for this to cause headaches when invoking non-static, non-virtual member function on illicit pointers. If the function is virtual, you'll generally (if you're fortunate) blow up on the call. If the function is non-virtual, you'll generally (if you're fortunate) blow up somewhere in the body of the function as it tries to access member data that isn't there (including a vtable-directed execution if your non-virtual calls a virtual).
To demonstrate this, consider this (obviously UB) example. Try it.
#include <iostream>
class NullClass
{
public:
void call_me()
{
std::cout << static_cast<void*>(this) << '\n';
std::cout << "How did I get *here* ???" << '\n';
}
};
int main()
{
NullClass *noObject = NULL;
noObject->call_me();
}
Output (OSX 10.10.1 x64, clang 3.5)
0x0
How did I get *here* ???
The bottom line is no vtable is bound to the object when you allocate raw memory and assign a pointer via a cast as you are. If you want to do this, you need to construct the object via placement-new. And in so doing, do not forget you must also destroy the object (which has nothing to do with the memory it occupies, as you're managing that separately) by calling its destructor manually.
Finally, the assignment you're invoking does not copy the vtable. Frankly there is no reason to. The vtable of a properly constructed object is already properly built, and referenced by the vtable pointer for a given object instance. Said-pointer does not participate in object copying, which has its own set of mandated requirements from the language standard.
new char[...]
This does not construct object T (does not calls constructor).
Virtual table is created during construction.
The problem is not specially with virtual functions but more generally with inheritance. As buffer is an array of A, when you write :
B b;
buffer[0] = b;
you first construct a B object (first line), and later construct an A object using its copy constructor initialized with b (second line).
So when you later call buffer[0].virtual_function() you actually apply the virtual function to an A object, not to aB one.
By the way, a direct call to b.virtual_function() should still correctly call the B version since it is applied to a real B object :
B b;
buffer[0] = b;
b.virtual_function(); // calls B version
If you do not need to take a copy of the object, you could use an array of pointers.
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.
I'm making a little wrapper class for sqlite. To get data to/from the database I have a class called SQLiteValue. When binding data for a query SQLiteValue instances get created on the stack and passed around a few functions. A skeleton outline of the class is below.
class SQLiteValue : public SQLiteObject
{
private:
// stores a pointer to the data contained (could be of varying types)
union
{
int* i;
double* d;
std::string* s;
std::wstring* ws;
BYTE* b;
} pdata;
int type;
public:
SQLiteValue(const char* val);
SQLiteValue(const wchar_t* val);
.. and so on for varying types
virtual ~SQLiteValue();
};
The object gets created by one of several overloaded constructors. The constructors instantiate a "member" of pdata based on their type. This is the important thing for this class. Now, the problem. I have the constructors overloaded so I get clean method calls and don't need to explicitly call SQLiteValue(xxx). As such I don't really want to use references for functions, so I define them like.
void BindValue(const char* name, SQLiteValue value)
query->BindValue(":username", "user2"); // the "clean" method call
Declaring them like this causes a new object to be instantiated every time (or something similar?) I call a function and so the destructor frees memory allocated for pdata. This is bad.
What I'd like to know is this. Is there a better way to achieve what I'm trying to do whilst retaining my clean method calls? At the moment I have private functions which operate by reference which solves the issue, but I don't really like this method. It would be easy for me to forget the reference and I'd end up tracking down this same issue again.
Thanks.
Change BindValue to take parameter by const reference.
void BindValue(const char* name, const SQLiteValue &value)
This is situation when rvalue reference can help. It doesn't reduce amount of constructors/destructors called, but allows to "steal" internal resources of temporary class instances in rvalue (&&) copy constructor or operator=. See details here: http://blogs.msdn.com/b/vcblog/archive/2009/02/03/rvalue-references-c-0x-features-in-vc10-part-2.aspx
rvalue reference copy constructor just moves another instance internal resources to "this" instance, and resets another instance resources to 0. So, instead of allocation, copying and releasing, it just copies a pointer or handle. "user2" in your code is such temporary instance - rvalue reference.
This can be applied to any C++ compiler implementing C++0x standard.