To understand the problems with object slicing, I thought I have created a horrible example and I was trying to test it. However, the example is not as bad as I thought it would be.
Below is a minimal working example, and I would appreciate if you helped me understand why it is still "working properly". It would be even better if you helped me make the example worse.
#include <functional>
#include <iostream>
template <class T> class Base {
protected:
std::function<T()> f; // inherited
public:
Base() : f{[]() { return T{0}; }} {} // initialized
virtual T func1() const { return f(); }
virtual ~Base() = default; // avoid memory leak for children
};
template <class T> class Child : public Base<T> {
private:
T val;
public:
Child() : Child(T{0}) {}
Child(const T &val) : Base<T>{}, val{val} { // initialize Base<T>::f
Base<T>::f = [&]() { return this->val; }; // copy assign Base<T>::f
}
T func1() const override { return T{2} * Base<T>::f(); }
void setval(const T &val) { this->val = val; }
};
template <class T> T indirect(const Base<T> b) { return b.func1(); }
int main(int argc, char *argv[]) {
Base<double> b;
Child<double> c{5};
std::cout << "c.func1() (before): " << c.func1() << '\n'; // as expected
c.setval(10);
std::cout << "c.func1() (after): " << c.func1() << '\n'; // as expected
std::cout << "indirect(b): " << indirect(b) << '\n'; // as expected
std::cout << "indirect(c): " << indirect(c) << '\n'; // not as expected
return 0;
}
The output I get when I compile the code is as follows:
c.func1() (before): 10
c.func1() (after): 20
indirect(b): 0
indirect(c): 10
I would expect the last line to throw some exception or simply fail. When the base part of c gets sliced in indirect, there is no this->val to be used inside the lambda expression (I know, C++ is a statically compiled language, not a dynamic one). I have also tried capturing this->val by value when copy assigning Base<T>::f, but it did not change the result.
Basically, my question is two folds. First, is this undefined behaviour, or simply a legal code? Second, if this is a legal code, why is the behaviour not affected by slicing? I mean, I can see that T func1() const is called from the Base<T> part, but why is the captured value not causing any trouble?
Finally, how can I build an example to have worse side-effects such as memory access type of problems?
Thank you in advance for your time.
EDIT. I am aware of the other topic that has been marked as duplicate. I have read all the posts there, and in fact, I have been trying to duplicate the last post there. As I have asked above, I am trying to get the behaviour
Then the information in b about member bar is lost in a.
which I cannot get fully. To me, only partial information seems to be lost. Basically, in the last post, the person claims
The extra information from the instance has been lost, and f is now prone to undefined behaviour.
In my example, f seems to be working just as well. Instead, I just have the call to T Base<T>::func1() const, which is no surprise.
There is no undefined behavior with your current code. However, it's dangerous and therefore easy to make undefined behavior with it.
The slicing happen, and yet you access this->val. Seems like magic, but you're just accessing the this->val from Child<double> c from your main!
That's because of the lambda capture. You capture this, which points to your c variable in your main. You then assign that lambda into a std::function inside your base class. You base class now have a pointer to the c variable, and a way to access the val through the std::function.
So the slicing occurs, but you access to the unsliced object.
This is also why the number is not multiplied by two. The virtual call resolves to base, and the value of val in c in your main is 10.
Your code is roughly equivalent to that:
struct B;
struct A {
B* b = nullptr;
int func1() const;
};
struct B : A {
int val;
explicit B(int v) : A{this}, val{v} {}
};
int A::func1() const {
return b->val;
}
int main() {
B b{10};
A a = b;
std::cout << a.func1() << std::endl;
}
Related
I am trying a sort of type-erasure with some function pointers and templates as given in the example below. What I find strange is with GCC i get wrong result where as with VS 2017, I get the expected one. So, who is correct and who is wrong and why ?
Live example on COLIRU: http://coliru.stacked-crooked.com/a/225db5711c07c8b0
struct A { void PrintA() { std::cout << "Event A" << std::endl; } };
struct B { void PrintB() { std::cout << "Event B" << std::endl; } };
struct C { void PrintC() { std::cout << "Event C" << std::endl; } };
struct RunBase
{
virtual void operator()() = 0;
};
template <typename T>
struct Run : public RunBase
{
using FUNC = void (T::*)();
Run(T& o, FUNC&& f) : mObj(o), mFunc(f) {}
void operator()() override { (mObj.*mFunc)(); }
T& mObj;
FUNC& mFunc;
};
int main()
{
A a;
B b;
C c;
std::vector<std::unique_ptr<RunBase> > mFuncs;
mFuncs.push_back(std::make_unique<Run<A> >(a, &A::PrintA));
mFuncs.push_back(std::make_unique<Run<B> >(b, &B::PrintB));
mFuncs.push_back(std::make_unique<Run<C> >(c, &C::PrintC));
for (auto& i : mFuncs)
(*i)();
return 0;
}
Expected result:
Event A
Event B
Event C
But GCC gives me:
Event C
Event C
Event C
It's because you store a reference inside your object, but &A::PrintA etc. are temporaries which are destroyed at the end of the full expression, and so the member reference is left dangling, and its use results in undefined behaviour.
Simply store a copy of the member function pointer to fix it:
FUNC mFunc;
PS. When mFuncs is destroyed, the unique pointers delete child objects through a base pointer. The behaviour is undefined unless you declare RunBase::~RunBase virtual.
So, who is correct and who is wrong and why ?
Your program is wrong; There is no correct behaviour for it.
My solution I gonna use to add “C++ Extension Methods” to JNI jobjects to make NDK code more readable like (Uniform Function Call Syntax) is:
Subclass the class that I want to add extension methods.
For invoking the “Extension Methods” make a pointer of type ExtensionsClass to point to OriginalClass - (Although the pointed object is’nt an ExtensionsClass).
The overload is minimal & we can access public methods of the Original class.
#include <iostream>
// Represents a class external to my source
class Person {
public:
Person(){
privateage = 20;
}
int age() { return privateage; }
private:
int privateage;
short anotherField;
};
class PersonExtensions : private Person {
public:
inline int size() { return 5 + age(); }
//NoFieldsOnExtensionClass
};
int main() {
Person person;
PersonExtensions* pE = (PersonExtensions*) &person;
std::cout << pE -> size() << std::endl;
std::cout << (*pE).size() << std::endl;
std::cout << sizeof(Person) << std::endl;
std::cout << sizeof(PersonExtensions) << std::endl;
return 0;
}
Do you think that this incorrect pointer assignment, since “Extension Method” only accessed public members of extended class & extension class don’t going to have any Field variables, can represent a problem in the future?
The size of the object are the same.
Thanks a lot.
This is undefined behaviour.
Yes that can break at any point.
Consider overloading ->* or something instead.
Or just using a free function.
If you really want infix notation:
template<class T, class F>
struct extension_method_t {
F f;
friend auto operator->*( T& t, extension_method_t const& self ) {
return [&t,&self](auto&&...args)->decltype(auto) {
return self.f( t, decltype(args)(args)... );
};
}
};
template< class T, class F >
extension_method_t<T,F> extension_method( F f ) {
return {std::move(f)};
}
then:
auto size = extension_method<Person>([](auto& person)->int{
return 5+person.age();
});
Person p;
std::cout << (p->*size)() << "\n"; // prints p.age()+5
here we don't have an extension method, but we do have an extension method pointer.
What you are doing in your question code is Undefined Behavior, so an especially an optimizing compiler might do really "fun" things with it. In other words, don't do it, it might break at any time even if it works when you test it. Only way to make sure it would actually work would be to examine the produced assembly code after each compilation to make sure it does what you want, and this is essentially impossible, so it is never safe.
You are using private inheritance. So for same effect you can just do this:
class PersonExtensions {
public:
PersonExtensions(Person *person) : _person(person) {}
inline int size() { return 5 + _person->age(); }
private:
Person *_person;
};
If you instead used public inheritance (so you could just call Person methods through PersonExtensions), then you'd need to add a getter for _person (for cases where real Person is needed), and/or add delegates for Person methods (for so called static polymorphism).
So, I've been experimenting with static class fields (especially the constant ones), and got myself into.... this:
#include <iostream>
#include <conio.h>
class Test {
public:
Test() { std::cout << "Constructing (Default CTOR)\n"; }
Test(int f) { std::cout << "Constructing (Int arg CTOR)\n"; }
void method() const { std::cout << "Already constructed and being used\n"; }
};
class Stack {
public:
// static const Test what{ 5 }; // - "element of type "const Test" can not have an initializer inside of a class"
// const Test ok{ 5 }; // now it can (?)
static const Test what;
Stack() {
what.method();
}
// Stack() : what{5} {} // can't do that because "what" will be dependent on object creation (which is not how static class fields roll)
};
Stack obj;
const Test Stack::what{};
int main()
{
_getch();
return 0;
}
Output:
Apparently, static const Test what in Stack is being used before is has actually been created(?).
After that I ran another test:
#include <iostream>
#include <conio.h>
class Test {
public:
int data;
Test() { std::cout << "CONSTRUCTING (Default CTOR)\n"; } // notice, value-initialization of 'data' has been removed
Test(int f) : data{ f } { std::cout << "CONSTRUCTING (Int arg CTOR)\n"; }
void method() const { std::cout << "ALREADY CONSTRUCTED AND BEING USED :)\n" << data << std::endl; }
};
class Stack {
public:
static const Test what;
Stack() {
what.method();
}
};
Stack obj;
const Test Stack::what{ 5 };
int main()
{
obj.what.method();
_getch();
return 0;
}
In this code I was hoping to see some sort of error, but the output ended up looking like this:
I have some assumptions on what is happening here, but I'm not sure if they're correct. So, if they are, please correct me.
Here are my assumptions:
Basically, static variables are created at the very start of the program (and are value-initialized) and destoyed at the very end of the program (when you actually close your .exe).
In my examples I have a static constant variable what in the class Stack and I think it is being created at the beginning of my program value-initialized. That's why its data field is set 0 and we can use its methods. But I don't think that's correct because it would've output Constructing (Default CTOR) into the console. So I'm kinda stuck there...
I also can not understand why the commented lines in my first example are illegal. What rules of static/constant class fields do they break exactly?
If you have any idea to what is happening in my examples please explain it.
Thanks for your attention.
Static variables at namespace scope (i.e. not inside a function) are constructed in the order of their definitions in the source file. This ordering only applies between variables in the same source file, not between different source files.
So obj is always constructed before what. There are limited things that can be done with objects that have a constructor but before the constructor has been called; and invoking a member function is not one of them (C++14 [basic.life]/5.2). So the call what.method() in Stack's constructor causes undefined behaviour.
Consider the following class structure:-
class foo {
public:
int fun () {
cout << "in foo" << endl;
}
};
class bar_class1:public foo {
public:
int fun () {
cout << "in bar_class1" << endl;
}
};
class bar_class2:public foo {
public:
float fun () {
cout << "in bar_class2" << endl;
}
};
main () {
foo * foo_pointer = new bar_class1();
foo_pointer->fun();
}
The output of the above program is in foo. Is there a way, that using a pointer of type foo * which actually points to an object of type bar_class1 or bar_class2, we can call the fun function of the derived class instead of the base class? I am not able to make the fun function virtual in the base class foo since, then there is a return type conflict for function foo in the derived class bar_class2.
Here's my comments as an answer.
You cannot do that.
If that kind of polymorphism were possible, wouldn't that break horribly when code calls foo::fun (expecting an int) on an object whose actual type is bar_class2 and thus gets a float? Do you want to simply throw away type safety?
If you want different return types, sounds like you want a template. But you cannot use templates quite in the way that you want to use foo(). Static polymorphism (templates) and run time polymorphism (late binding) don't mix well. You need to redesign your oop structure.
If you absolutely hate type safety, you can sort of do this with void pointers. But for the love of Flying Spaghetti Monster, don't ever do this in c++. Please close your eyes before reading the following code to avoid exposure.
#include <iostream>
class foo {
public:
virtual void* fun() = 0;
virtual ~foo(){};
};
class bar_class1: public foo {
public:
void* fun() {
return &value;
}
private:
int value = 1;
};
class bar_class2: public foo {
public:
void* fun() {
return &value;
}
private:
float value = 1.1;
};
int main() {
foo* foo_pointer1 = new bar_class1();
foo* foo_pointer2 = new bar_class2();
// in c++ compiler must know the type of all objects during compilation
std::cout << *reinterpret_cast<int*>(foo_pointer1->fun()) << '\n';
std::cout << *reinterpret_cast<float*>(foo_pointer2->fun()) << '\n';
delete foo_pointer1;
delete foo_pointer2;
}
Perhaps similar to the existing answer, I really hope you realize changing your design is better than this mess, but I believe it's the best you're going to get. I force you to specify the return type at the callsite (e.g., someFoo->fun<int>()), since you're going to have to know it anyway, and dispatch based on that. Any funny business and you'll get an exception. Also keep in mind the performance of this is, I imagine, less than desirable.
#include <cassert>
#include <stdexcept>
#include <type_traits>
struct foo {
virtual ~foo() = default;
template<typename T, typename = typename std::enable_if<std::is_same<T, int>::value>::type, typename = void>
T fun();
template<typename T, typename = typename std::enable_if<std::is_same<T, float>::value>::type>
T fun();
};
struct bar_class1 : foo {
int fun() {
return 2;
}
};
struct bar_class2 : foo {
float fun() {
return 3.5f;
}
};
template<typename T, typename, typename Dummy>
T foo::fun() {
if (auto *p = dynamic_cast<bar_class1 *>(this)) {
return p->fun();
} else if (dynamic_cast<bar_class2 *>(this)) {
throw std::invalid_argument("Mismatching dynamic type.");
} else {
return 1;
}
}
template<typename T, typename>
T foo::fun() {
auto *p = dynamic_cast<bar_class2 *>(this);
if (dynamic_cast<bar_class1 *>(this) || !p) {
throw std::invalid_argument("Mismatching dynamic type.");
} else if (auto *p = dynamic_cast<bar_class2 *>(this)) {
return p->fun();
}
assert(false); //should never get here, but compiler doesn't know that
}
If you'd like the main function, I've written a complete sample.
To answer your question: No, late binding isn't possible without deciding the return type. ...at least not in a reasonable manner, see user2079303's great counter-example. But...
you may change your code (for example) into something like the following, using the keyword virtual and equalize the return type for instance to void:
class foo
{
public:
virtual void fun(std::ostream& out) {
out << "in foo" << std::endl;
}
};
so you can decide the output type later:
class intFoo: public foo
{
public:
void fun(std::ostream& out) {
// output an int
out << "in bar_class1. data: " << data << endl;
}
int data;
};
class floatFoo: public foo
{
public:
void fun(std::ostream& out) {
// output a float
out << "in bar_class2. data: " << data << endl;
}
float data;
};
For brevity, I double-use the output stream - now a parameter of the function fun() - function to demonstrate type-dependent portion of your derived class. In your application, the parameter will probably be of another, more useful type.
The function fun is not a virtual function since you didn't use the keyword "virtual" to decorate it. So, the compile will determine which function to call at compiling time. So, there is no way to tell the compiler to call another function because the compiler will use its static type, i.e. the variable definition type -- foo *.
I have a class Model:
class Model
{
...
boost::shared_ptr<Deck> _deck;
boost::shared_ptr<CardStack> _stack[22];
};
Deck inherits from CardStack.
I tried to make _stack[0] point to the same thing that _deck points to by going:
{
_deck = boost::shared_ptr<Deck>(new Deck());
_stack[0] = _deck;
}
It seems that the assignment to _deck of _stack[0] results in a copy of _deck being made. (I know this because modifications to _stack[0] do not result in modifications to _deck.) How can I get them to point to the same thing?
Ok - no copy constructor is being called. I have verified this by implementing it and seeing if it gets called - it doesn't.
However - I have a function that operates on CardStack objects:
void TransferSingleCard(CardStack & src, CardStack & dst, Face f)
{
if( !src._cards.empty() )
{
src._cards.back().SetFace(f);
dst.PushCard(src._cards.back());
src._cards.pop_back();
}
}
Now - when I call:
{
TransferSingleCard(*_stack[DECK], _someotherplace, FACEDOWN);
std::cout << *_stack[DECK];
std::cout << *_deck;
}
I get this output (where std::cout on a CardStack will print out the size of that stack):
Num(103) TOP
Num(104) TOP
... so I've concluded (incorrectly?) that _stack[DECK] points to something different.
The Deck
class Deck : public CardStack
{
public:
Deck(int numsuits=2, StackIndex index = NO_SUCH_STACK );
Deck::Deck( const Deck & d);
int DealsLeft() const;
void RecalcDealsLeft();
private:
int _dealsleft;
};
Not clear what you are asking about - consider this code:
#include <iostream>
#include "boost/shared_ptr.hpp"
using namespace std;
struct A {
virtual ~A() {
cout << "destroyed" << endl;
}
};
struct B : public A {
};
int main() {
boost::shared_ptr<B> b( new B );
boost::shared_ptr<A> a;
a = b;
}
Only one "destroy" message appears, indicating that no copy has been made.
This example - derives from #Neil's answer, tries to emulate what you say is happening. Could you check that it works as expected (A and B have the same count) on your system.
Then we could try and modify this code or your code until they match.
#include <boost/shared_ptr.hpp>
#include <iostream>
class A {
public:
virtual ~A()
{
std::cerr << "Delete A" << std::endl;
}
int _count;
void decrement()
{
_count --;
}
};
class B : public A {
public:
virtual ~B()
{
std::cerr << "Delete B" << std::endl;
}
};
int main()
{
boost::shared_ptr<B> b(new B);
b->_count = 104;
boost::shared_ptr<A> a;
a = b;
a->decrement();
std::cerr << "A:" << a->_count << std::endl;
std::cerr << "B:" << b->_count << std::endl;
return 0;
}
EDIT:
So from the comment, we know the original pointers are correct, so now we need to trace.
Either:
log pointers to see when they change.
Use watchpoints in a debugger to see when the pointer changes.
Use a third shared pointer to see which pointer is changed.
Introduce a function that changes both pointers at the same time.
I think the problem is that you're assigning between different types here. boost::shared_ptr is a template and templates are not polymorphic even if the type in them is. So what's happening is that your compiler sees the assignment from boost::shared_ptr<Deck> to boost::shared_ptr<CardStack> and notices that it can make the assignment by calling the copy constructor for CardStack to duplicate the Deck object.
I think what you want the assignment to look like is something like this:
_stack[0] = boost::static_pointer_cast<CardStack>(_deck);
Which will do the conversion the way you expect it to.
I think you may want shared_array for _stack . . . Take a look at the documentation on shared_ptr;from boost.org, specifically:
http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/shared_ptr.htm
"Normally, a shared_ptr cannot
correctly hold a pointer to a
dynamically allocated array. See
shared_array for that usage."
Also, be aware of the T* get() function (not to be used without good reason) which returns the raw pointer being held by the managed pointer (shared_ptr in this case).