Avoiding vtable pointers in objects in C++
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
0
down vote
favorite
In my previous question, it was highlight that implementations of C++ such as GCC must store a vtable pointer in every copy of a class for each parent class which has a virtual function.
So a class which implements say 5 "interfaces" (i.e. pure abstract classes) must be at least 5 pointers in size before even it's own members are added.
At first glance, this seems necessary. When we upcast, all we can do is change the pointer. But we need a new vtable for that upcasted pointer. So there's not much option other than putting it in the object itself.
The downside of this is that we pay a per-object cost for virtual parent classes, even ones with no members.
How about instead, making a pointer "two pointers". The first pointer is a pointer to the object. The second is a pointer to it's vtable. This could perhaps only be done for virtual objects.
The object itself could now just be pure data, no need for vtable pointers.
Note then we only need one vtable pointer, even if there's multiple parents. The vtable itself could have entries describing how to upcast, or perhaps the compiler just knows how to do this.
Is there any reason this approach is not viable> Are there any C++ implementations that do this?
(Note: I understand one can avoid pure abstract bases as interfaces and "duck typing" and in the future concepts but lets ignore that for the moment)
object-oriented c++ interfaces multiple-inheritance
add a comment |Â
up vote
0
down vote
favorite
In my previous question, it was highlight that implementations of C++ such as GCC must store a vtable pointer in every copy of a class for each parent class which has a virtual function.
So a class which implements say 5 "interfaces" (i.e. pure abstract classes) must be at least 5 pointers in size before even it's own members are added.
At first glance, this seems necessary. When we upcast, all we can do is change the pointer. But we need a new vtable for that upcasted pointer. So there's not much option other than putting it in the object itself.
The downside of this is that we pay a per-object cost for virtual parent classes, even ones with no members.
How about instead, making a pointer "two pointers". The first pointer is a pointer to the object. The second is a pointer to it's vtable. This could perhaps only be done for virtual objects.
The object itself could now just be pure data, no need for vtable pointers.
Note then we only need one vtable pointer, even if there's multiple parents. The vtable itself could have entries describing how to upcast, or perhaps the compiler just knows how to do this.
Is there any reason this approach is not viable> Are there any C++ implementations that do this?
(Note: I understand one can avoid pure abstract bases as interfaces and "duck typing" and in the future concepts but lets ignore that for the moment)
object-oriented c++ interfaces multiple-inheritance
In practice it does not matter: multiple inheritance is rarely used, and in the few cases it is used the object is usually quite "big" -data fields are also inherited- (and the multiple superclasses are few, more often 2 than 5).
â Basile Starynkevitch
Aug 6 at 13:36
add a comment |Â
up vote
0
down vote
favorite
up vote
0
down vote
favorite
In my previous question, it was highlight that implementations of C++ such as GCC must store a vtable pointer in every copy of a class for each parent class which has a virtual function.
So a class which implements say 5 "interfaces" (i.e. pure abstract classes) must be at least 5 pointers in size before even it's own members are added.
At first glance, this seems necessary. When we upcast, all we can do is change the pointer. But we need a new vtable for that upcasted pointer. So there's not much option other than putting it in the object itself.
The downside of this is that we pay a per-object cost for virtual parent classes, even ones with no members.
How about instead, making a pointer "two pointers". The first pointer is a pointer to the object. The second is a pointer to it's vtable. This could perhaps only be done for virtual objects.
The object itself could now just be pure data, no need for vtable pointers.
Note then we only need one vtable pointer, even if there's multiple parents. The vtable itself could have entries describing how to upcast, or perhaps the compiler just knows how to do this.
Is there any reason this approach is not viable> Are there any C++ implementations that do this?
(Note: I understand one can avoid pure abstract bases as interfaces and "duck typing" and in the future concepts but lets ignore that for the moment)
object-oriented c++ interfaces multiple-inheritance
In my previous question, it was highlight that implementations of C++ such as GCC must store a vtable pointer in every copy of a class for each parent class which has a virtual function.
So a class which implements say 5 "interfaces" (i.e. pure abstract classes) must be at least 5 pointers in size before even it's own members are added.
At first glance, this seems necessary. When we upcast, all we can do is change the pointer. But we need a new vtable for that upcasted pointer. So there's not much option other than putting it in the object itself.
The downside of this is that we pay a per-object cost for virtual parent classes, even ones with no members.
How about instead, making a pointer "two pointers". The first pointer is a pointer to the object. The second is a pointer to it's vtable. This could perhaps only be done for virtual objects.
The object itself could now just be pure data, no need for vtable pointers.
Note then we only need one vtable pointer, even if there's multiple parents. The vtable itself could have entries describing how to upcast, or perhaps the compiler just knows how to do this.
Is there any reason this approach is not viable> Are there any C++ implementations that do this?
(Note: I understand one can avoid pure abstract bases as interfaces and "duck typing" and in the future concepts but lets ignore that for the moment)
object-oriented c++ interfaces multiple-inheritance
asked Aug 6 at 4:08
Clinton
5891610
5891610
In practice it does not matter: multiple inheritance is rarely used, and in the few cases it is used the object is usually quite "big" -data fields are also inherited- (and the multiple superclasses are few, more often 2 than 5).
â Basile Starynkevitch
Aug 6 at 13:36
add a comment |Â
In practice it does not matter: multiple inheritance is rarely used, and in the few cases it is used the object is usually quite "big" -data fields are also inherited- (and the multiple superclasses are few, more often 2 than 5).
â Basile Starynkevitch
Aug 6 at 13:36
In practice it does not matter: multiple inheritance is rarely used, and in the few cases it is used the object is usually quite "big" -data fields are also inherited- (and the multiple superclasses are few, more often 2 than 5).
â Basile Starynkevitch
Aug 6 at 13:36
In practice it does not matter: multiple inheritance is rarely used, and in the few cases it is used the object is usually quite "big" -data fields are also inherited- (and the multiple superclasses are few, more often 2 than 5).
â Basile Starynkevitch
Aug 6 at 13:36
add a comment |Â
2 Answers
2
active
oldest
votes
up vote
6
down vote
How about instead, making a pointer "two pointers".
This would bloat every pointer, even those which don't use dynamic polymorphism. Remember: you have to be able to cast any object pointer to void*
and back to that type with valid behavior. That wouldn't be possible unless every pointer used your "two pointer" approach. Plus, the C++ standard does not permit the size of an object pointer to be determined by what type it points to.
This would also break ABI with C and every C API function ever written. C++ implementations like to be able to call C APIs.
C++ is a language that prefers to follow the "don't pay for what you don't use" rule. Users who use lots of multiple inheritance of virtual interfaces pay for it; users who don't use these things don't have to pay anything. That is as it should be.
add a comment |Â
up vote
4
down vote
How about instead, making a pointer "two pointers".
Yes, I think that could be done, theoretically â there are a lot of ways C++ could be implemented. These choices are all trade-offs of one thing for another; though, there are lots of considerations to be made in such an implementation.
C++ avoids search across multiple inheritance parent classes by capitalizing on the point of conversion (from the concrete class to the (abstract) base). Other languages choose instead to search for an interface in the vtable of the concrete class (and instead do nothing at point of conversion), but pretty sure C++ could do that, too, if they wanted to, don't think there's any strict rule as to how it must be implemented. (FYI, Doing nothing at point of conversion tends to be somewhat friendlier to garbage collection, another reason this tends to be favored by C# and Java.)
However, C++ allows instance fields in (abstract) base classes, whereas C# and Java don't support instance fields for interfaces. This makes things a bit trickier for C++, since it has to know about data slots in the object as well as function slots in the vtable. Perhaps due to this, I think, C++'s usually settle on adjusting the object pointer at point of conversion, rather than searching for data slots and searching for virtual function slots.
Note that a single object implementing 5 different interfaces is, IMHO, overrated. You might find composition better for many scenarios, meaning that you would create several cooperating classes, each class implementing only one interface.
(Also note that the overhead you're describing only happens on the second parent class, not the first, as the subclass and its first base can share a vtable pointer.)
In any case, the overhead is minimal unless you're going to create a huge amount of these objects. Usually, objects created in great quantities can be optimized in various ways, such as the (albeit complex) flyweight pattern.
add a comment |Â
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
6
down vote
How about instead, making a pointer "two pointers".
This would bloat every pointer, even those which don't use dynamic polymorphism. Remember: you have to be able to cast any object pointer to void*
and back to that type with valid behavior. That wouldn't be possible unless every pointer used your "two pointer" approach. Plus, the C++ standard does not permit the size of an object pointer to be determined by what type it points to.
This would also break ABI with C and every C API function ever written. C++ implementations like to be able to call C APIs.
C++ is a language that prefers to follow the "don't pay for what you don't use" rule. Users who use lots of multiple inheritance of virtual interfaces pay for it; users who don't use these things don't have to pay anything. That is as it should be.
add a comment |Â
up vote
6
down vote
How about instead, making a pointer "two pointers".
This would bloat every pointer, even those which don't use dynamic polymorphism. Remember: you have to be able to cast any object pointer to void*
and back to that type with valid behavior. That wouldn't be possible unless every pointer used your "two pointer" approach. Plus, the C++ standard does not permit the size of an object pointer to be determined by what type it points to.
This would also break ABI with C and every C API function ever written. C++ implementations like to be able to call C APIs.
C++ is a language that prefers to follow the "don't pay for what you don't use" rule. Users who use lots of multiple inheritance of virtual interfaces pay for it; users who don't use these things don't have to pay anything. That is as it should be.
add a comment |Â
up vote
6
down vote
up vote
6
down vote
How about instead, making a pointer "two pointers".
This would bloat every pointer, even those which don't use dynamic polymorphism. Remember: you have to be able to cast any object pointer to void*
and back to that type with valid behavior. That wouldn't be possible unless every pointer used your "two pointer" approach. Plus, the C++ standard does not permit the size of an object pointer to be determined by what type it points to.
This would also break ABI with C and every C API function ever written. C++ implementations like to be able to call C APIs.
C++ is a language that prefers to follow the "don't pay for what you don't use" rule. Users who use lots of multiple inheritance of virtual interfaces pay for it; users who don't use these things don't have to pay anything. That is as it should be.
How about instead, making a pointer "two pointers".
This would bloat every pointer, even those which don't use dynamic polymorphism. Remember: you have to be able to cast any object pointer to void*
and back to that type with valid behavior. That wouldn't be possible unless every pointer used your "two pointer" approach. Plus, the C++ standard does not permit the size of an object pointer to be determined by what type it points to.
This would also break ABI with C and every C API function ever written. C++ implementations like to be able to call C APIs.
C++ is a language that prefers to follow the "don't pay for what you don't use" rule. Users who use lots of multiple inheritance of virtual interfaces pay for it; users who don't use these things don't have to pay anything. That is as it should be.
edited Aug 6 at 13:14
answered Aug 6 at 4:30
Nicol Bolas
8,71532733
8,71532733
add a comment |Â
add a comment |Â
up vote
4
down vote
How about instead, making a pointer "two pointers".
Yes, I think that could be done, theoretically â there are a lot of ways C++ could be implemented. These choices are all trade-offs of one thing for another; though, there are lots of considerations to be made in such an implementation.
C++ avoids search across multiple inheritance parent classes by capitalizing on the point of conversion (from the concrete class to the (abstract) base). Other languages choose instead to search for an interface in the vtable of the concrete class (and instead do nothing at point of conversion), but pretty sure C++ could do that, too, if they wanted to, don't think there's any strict rule as to how it must be implemented. (FYI, Doing nothing at point of conversion tends to be somewhat friendlier to garbage collection, another reason this tends to be favored by C# and Java.)
However, C++ allows instance fields in (abstract) base classes, whereas C# and Java don't support instance fields for interfaces. This makes things a bit trickier for C++, since it has to know about data slots in the object as well as function slots in the vtable. Perhaps due to this, I think, C++'s usually settle on adjusting the object pointer at point of conversion, rather than searching for data slots and searching for virtual function slots.
Note that a single object implementing 5 different interfaces is, IMHO, overrated. You might find composition better for many scenarios, meaning that you would create several cooperating classes, each class implementing only one interface.
(Also note that the overhead you're describing only happens on the second parent class, not the first, as the subclass and its first base can share a vtable pointer.)
In any case, the overhead is minimal unless you're going to create a huge amount of these objects. Usually, objects created in great quantities can be optimized in various ways, such as the (albeit complex) flyweight pattern.
add a comment |Â
up vote
4
down vote
How about instead, making a pointer "two pointers".
Yes, I think that could be done, theoretically â there are a lot of ways C++ could be implemented. These choices are all trade-offs of one thing for another; though, there are lots of considerations to be made in such an implementation.
C++ avoids search across multiple inheritance parent classes by capitalizing on the point of conversion (from the concrete class to the (abstract) base). Other languages choose instead to search for an interface in the vtable of the concrete class (and instead do nothing at point of conversion), but pretty sure C++ could do that, too, if they wanted to, don't think there's any strict rule as to how it must be implemented. (FYI, Doing nothing at point of conversion tends to be somewhat friendlier to garbage collection, another reason this tends to be favored by C# and Java.)
However, C++ allows instance fields in (abstract) base classes, whereas C# and Java don't support instance fields for interfaces. This makes things a bit trickier for C++, since it has to know about data slots in the object as well as function slots in the vtable. Perhaps due to this, I think, C++'s usually settle on adjusting the object pointer at point of conversion, rather than searching for data slots and searching for virtual function slots.
Note that a single object implementing 5 different interfaces is, IMHO, overrated. You might find composition better for many scenarios, meaning that you would create several cooperating classes, each class implementing only one interface.
(Also note that the overhead you're describing only happens on the second parent class, not the first, as the subclass and its first base can share a vtable pointer.)
In any case, the overhead is minimal unless you're going to create a huge amount of these objects. Usually, objects created in great quantities can be optimized in various ways, such as the (albeit complex) flyweight pattern.
add a comment |Â
up vote
4
down vote
up vote
4
down vote
How about instead, making a pointer "two pointers".
Yes, I think that could be done, theoretically â there are a lot of ways C++ could be implemented. These choices are all trade-offs of one thing for another; though, there are lots of considerations to be made in such an implementation.
C++ avoids search across multiple inheritance parent classes by capitalizing on the point of conversion (from the concrete class to the (abstract) base). Other languages choose instead to search for an interface in the vtable of the concrete class (and instead do nothing at point of conversion), but pretty sure C++ could do that, too, if they wanted to, don't think there's any strict rule as to how it must be implemented. (FYI, Doing nothing at point of conversion tends to be somewhat friendlier to garbage collection, another reason this tends to be favored by C# and Java.)
However, C++ allows instance fields in (abstract) base classes, whereas C# and Java don't support instance fields for interfaces. This makes things a bit trickier for C++, since it has to know about data slots in the object as well as function slots in the vtable. Perhaps due to this, I think, C++'s usually settle on adjusting the object pointer at point of conversion, rather than searching for data slots and searching for virtual function slots.
Note that a single object implementing 5 different interfaces is, IMHO, overrated. You might find composition better for many scenarios, meaning that you would create several cooperating classes, each class implementing only one interface.
(Also note that the overhead you're describing only happens on the second parent class, not the first, as the subclass and its first base can share a vtable pointer.)
In any case, the overhead is minimal unless you're going to create a huge amount of these objects. Usually, objects created in great quantities can be optimized in various ways, such as the (albeit complex) flyweight pattern.
How about instead, making a pointer "two pointers".
Yes, I think that could be done, theoretically â there are a lot of ways C++ could be implemented. These choices are all trade-offs of one thing for another; though, there are lots of considerations to be made in such an implementation.
C++ avoids search across multiple inheritance parent classes by capitalizing on the point of conversion (from the concrete class to the (abstract) base). Other languages choose instead to search for an interface in the vtable of the concrete class (and instead do nothing at point of conversion), but pretty sure C++ could do that, too, if they wanted to, don't think there's any strict rule as to how it must be implemented. (FYI, Doing nothing at point of conversion tends to be somewhat friendlier to garbage collection, another reason this tends to be favored by C# and Java.)
However, C++ allows instance fields in (abstract) base classes, whereas C# and Java don't support instance fields for interfaces. This makes things a bit trickier for C++, since it has to know about data slots in the object as well as function slots in the vtable. Perhaps due to this, I think, C++'s usually settle on adjusting the object pointer at point of conversion, rather than searching for data slots and searching for virtual function slots.
Note that a single object implementing 5 different interfaces is, IMHO, overrated. You might find composition better for many scenarios, meaning that you would create several cooperating classes, each class implementing only one interface.
(Also note that the overhead you're describing only happens on the second parent class, not the first, as the subclass and its first base can share a vtable pointer.)
In any case, the overhead is minimal unless you're going to create a huge amount of these objects. Usually, objects created in great quantities can be optimized in various ways, such as the (albeit complex) flyweight pattern.
edited Aug 6 at 13:44
answered Aug 6 at 4:53
Erik Eidt
19.9k32949
19.9k32949
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsoftwareengineering.stackexchange.com%2fquestions%2f376441%2favoiding-vtable-pointers-in-objects-in-c%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
In practice it does not matter: multiple inheritance is rarely used, and in the few cases it is used the object is usually quite "big" -data fields are also inherited- (and the multiple superclasses are few, more often 2 than 5).
â Basile Starynkevitch
Aug 6 at 13:36