Bad value printed after referring to derived class through base class [duplicate] - c++

This question already has answers here:
Does a const reference class member prolong the life of a temporary?
(6 answers)
Closed 4 years ago.
After encountering a similar situation in a real-world application I decided to put together a demo which shows that if I store derived classes as a pointer to the base class, and call a virtual method the behavior of the derived class will be incorrect. See the code below:
struct IntWrapper { int value; };
struct Base {
virtual ~Base() = default;
virtual void myMethod() = 0;
};
struct Foo : public Base {
const IntWrapper& x;
Foo(const IntWrapper& x) : x(x) {}
void myMethod() override {
std::cout << std::to_string(x.value) << std::endl;
}
};
struct Bar : public Base {
const IntWrapper& x;
const IntWrapper& y;
Bar(const IntWrapper& x, const IntWrapper& y) : x(x), y(y) {}
void myMethod() override {
std::cout << std::to_string(x.value) << " " << std::to_string(y.value) << std::endl;
}
};
int main()
{
Base* foo = new Foo(IntWrapper{3});
Base* bar = new Bar(IntWrapper{5}, IntWrapper{42});
foo->myMethod();
bar->myMethod();
return 0;
}
The expected output would be:
3
5 42
Instead I receive:
42
5 42
Interestingly, if I replace IntWrapper reference with a primitive int in the classes Foo and Bar the printed values will be correct. Can somebody explain to me why this behavior happens?

Base* foo = new Foo(IntWrapper{3});
Base* bar = new Bar(IntWrapper{5}, IntWrapper{42});
You're creating an IntWrapper temporary that you're passing as a reference to the constructors, that save that reference for later use. As the temporary gets destructed after the constructor, your references inside foo and bar are invalid, and you're invoking undefined behavior, meaning anyhting can happen.
You need to either create IntWrapper variables that you will pass to the constructors, like so:
IntWrapper x{3};
IntWrapper y{5};
IntWrapper z{42};
Base* foo = new Foo(x);
Base* bar = new Bar(y,z);
Or your classes should make copies of passed IntWrappers, instead of holding a reference to them.

All of your member references are dangling, hence you have UB. – Passer By
and
Base* foo = new Foo(IntWrapper{3}); creates a temporary IntWrapper (destroyed at the end of the full expression); you save a reference to this temporary in foo. When you next use foo the saved reference is dangling (as the temporary has been destroyed) and you have Undefined Behaviour. - Richard Critten
I added a little bit printf debugging to the sample code of OP for demonstration. Now, the effects described in comments become quite obvious (IMHO):
#include <iostream>
struct IntWrapper {
int value;
IntWrapper(int value): value(value)
{
std::cout << "IntWrapper::IntWrapper(" << value << ")\n";
}
~IntWrapper()
{
std::cout << "IntWrapper::~IntWrapper(" << value << ")\n";
}
};
struct Base {
Base(const char *text)
{
std::cout << text << "::" << text << "()\n";
}
virtual ~Base() = default;
virtual void myMethod() = 0;
};
struct Foo : public Base {
const IntWrapper& x;
Foo(const IntWrapper& x): Base("Foo"), x(x) { }
void myMethod() override {
std::cout << std::to_string(x.value) << std::endl;
}
};
struct Bar : public Base {
const IntWrapper& x;
const IntWrapper& y;
Bar(const IntWrapper& x, const IntWrapper& y): Base("Bar"), x(x), y(y) {}
void myMethod() override {
std::cout << std::to_string(x.value) << " " << std::to_string(y.value) << std::endl;
}
};
int main()
{
Base* foo = new Foo(IntWrapper{3});
Base* bar = new Bar(IntWrapper{5}, IntWrapper{42});
std::cout << "foo->myMethod();\n";
foo->myMethod();
std::cout << "bar->myMethod();\n";
bar->myMethod();
return 0;
}
Output:
IntWrapper::IntWrapper(3)
Foo::Foo()
IntWrapper::~IntWrapper(3)
IntWrapper::IntWrapper(5)
IntWrapper::IntWrapper(42)
Bar::Bar()
IntWrapper::~IntWrapper(42)
IntWrapper::~IntWrapper(5)
foo->myMethod();
3
bar->myMethod();
5 42
Live Demo on coliru
Note:
The fact that the sample matched the expected output should not be mis-interpreted. It's still undefined behavior.

Related

How can a local object to a function survive when it is passed to an argument by reference

Problem Description
I started learning C++. But I have a problem with References. I have two classes A and B. What I am doing is that I am instantiating an object A in referenceTest. I also passed an object B by reference, which is instantiated in main. B has a function addA which initializes it's member variable _a and uses the local object A in referenceTest to achieve this task.
Question
The output std::cout << b.a().X() << std::endl; is printing 10. ​A is instantiated locally. So it should be destroyed after leaving referenceTest. I didn't understand. How come I was able to print 10? B is passed by reference and it is referecing a local variable. I don't understand what I am missing in here.
Source Code
// Online C++ compiler to run C++ program online
#include <iostream>
class A {
public:
A() {}
int X() const {return _x;}
void setX(int x){_x = x;}
private:
int _x;
};
class B{
public:
B(){}
void addA(A & a) {
_a = a;
}
A a() const {return _a;}
private:
A _a;
};
void referenceTest(B &b) {
A a;
a.setX(10);
b.addA(a);
}
int main() {
B b;
referenceTest(b);
std::cout << b.a().X() << std::endl;
return 0;
}

Factory pattern with abstract base classes - return by ref or by value? Problems with scoping and slicing

I have a type hierarchy similar to the code sample below, and I'm trying to instantiate them via the factory pattern (or, to be pedantic, rather the builder pattern, as my factory takes input from an XML document... but I digress).
However I try to do this, I'm running into problems which I suspect are due to either slicing, if I return by value, or to scoping, if I return by reference.
The below program, for instance, segfaults on the line a.doA() inside C::doStuff(). If I change the call to value_C_factory<C>() to ref_C_factory<C>() instead, I get a couple of warnings to the effect of "returning reference to temporary", but the program compiles, segfaults instead on b.doB() on the next line (without having printed anything from a.doA()...).
The backtrace from gdb looks like this - the second line is the one in my code referred to above
#0 0x00007ffff7dbddb0 in vtable for std::ctype<char> () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#1 0x00000000004010e9 in C::doStuff (this=0x7fffffffdd00) at syntax.cpp:57
#2 0x0000000000400cf2 in main () at syntax.cpp:95
What is causing these segfaults? Is it, as I suspect, slicing/scoping in the value/reference case? If not, what is it? And most importantly, what is a good way to build my instances from the input data?
Code sample
The code below should compile and give the above behavior with e.g. GCC 4.8, using
gcc -g -Wall -std=c++11 -o test test.cpp (that's what I do, anyway).
#include <iostream>
#include <typeinfo>
class IA {
public:
virtual void doA() const = 0;
virtual ~IA() { }
};
class A : public IA {
private:
std::string atask;
public:
explicit A(const std::string &task) : atask(task) {
std::cout << "Created A with task " << atask << std::endl;
}
void doA() const {
std::cout << "I did A! " << atask << std::endl;
}
};
class IB {
public:
virtual void doB() const = 0;
virtual ~IB() { }
};
class B : public IB {
private:
std::string btask;
public:
explicit B(const std::string &task) : btask(task) {
std::cout << "Created B with task " << btask << std::endl;
}
void doB() const {
std::cout << "I did B! " << btask << std::endl;
}
};
class IC {
public:
void doStuff() const;
virtual ~IC() { }
};
class C : public IC {
private:
const IA &a;
const IB &b;
public:
C(const IA &a, const IB &b) : a(a), b(b) { }
void doStuff() const {
a.doA(); // with value factory method, segfault here
b.doB(); // with reference factory, segfault here instead
}
};
template<typename TA>
TA value_A_factory() {
return TA("a value");
}
template<typename TB>
TB value_B_factory() {
return TB("b value");
}
template<typename TC>
TC value_C_factory() {
return TC(value_A_factory<A>(), value_B_factory<B>());
}
template<typename TA>
const TA &ref_A_factory() {
return TA("a ref");
}
template<typename TB>
const TB &ref_B_factory() {
return TB("b ref");
}
template<typename TC>
const TC &ref_C_factory() {
const TC &c(ref_A_factory<A>(), ref_B_factory<B>());
return c;
}
int main() {
C c = value_C_factory<C>();
std::cout << typeid(c).name() << std::endl;
c.doStuff();
}
You have two problems, both caused by undefined behavior.
The first is that you can't return a reference to a local variable. Once the function returns and the local variable goes out of scope and is destructed, what does the returned reference then reference?
The other problem is that you store references to temporary values. When you create your C class like TC(value_A_factory<A>(), value_B_factory<B>()) the values returned by the value_X_factory functions are temporary, and will be destroyed once the complete expression (TC(...)) is done.
In
template<typename TA>
const TA &ref_A_factory() {
return TA("a ref");
}
returning a reference to a local variable is undefined behavior.
In
TC(value_A_factory<A>(), ...)
the lifetime of the value returned by value_A_factory will be the end of the expression TC(...). After that your references in C are dangling.
If you really want to use interfaces and factories for polymorphic types, there is no real alternative to dynamic memory allocation and some kind of ownership scheme. The simplest would be for C to simply assume ownership of its members and take care of their deletion.
#include <memory>
#include <cassert>
struct IA {
virtual void doA() const = 0;
virtual ~IA() { };
};
struct A : IA {
void doA() const override {}
};
struct C {
/* C assumes ownership of a. a cannot be null. */
C(IA* a) : a{a} { assert(a && "C(IA* a): a was null"); };
private:
std::unique_ptr<IA> a;
};
C factory() {
return C{new A};
}
int main()
{
C c = factory();
return 0;
}

Misunderstood the virtual functions work in vector

I have following code on c++:
#include <iostream>;
#include <vector>;
class A
{
public:
A(int n = 0) : m_n(n) { }
public:
virtual int value() const { return m_n; }
virtual ~A() { }
protected:
int m_n;
};
class B
: public A
{
public:
B(int n = 0) : A(n) { }
public:
virtual int value() const { return m_n + 1; }
};
int main()
{
const A a(1);
const B b(3);
const A *x[2] = { &a, &b };
typedef std::vector<A> V;
V y;
y.push_back(a);
y.push_back(b);
V::const_iterator i = y.begin();
std::cout << x[0]->value() << x[1]->value()
<< i->value() << (i + 1)->value() << std::endl;
system("PAUSE");
return 0;
}
The compiler returned result: 1413.
I am little bit confused, because I thought the right result would be 1414 (as the function virtual). How do you explain this program behavior?
You are slicing the object, in order to get polymorphism you need to use either a pointer or a reference. This example keeping as close as possible to your original example and using a pointer will act as you wanted:
const A a(1);
const B b(3);
typedef std::vector<const A*> V;
V y;
y.push_back(&a);
y.push_back(&b);
V::iterator i = y.begin();
std::cout << (*i)->value() << std::endl ;
++i ;
std::cout << (*i)->value() << std::endl ;
To show briefly how the object slicing works here:
const A a(1);
const B b(3);
std::vector<A> y; // so y contains objects of type A
y.push_back(a); // y[0] is copy-constructed from a
y.push_back(b); // y[1] is copy-constructed from b
Note that in both push_back calls, it's always an A being constructed, via the automatically-generated A::A(const A&) copy constructor.
Note also that a B is-a A, which is to say b can be implicitly cast to an A and passed into the same copy-constructor.
So, y[1] is an instance of A with the m_n value copied from b, but its virtual function is still A::value. If you have constructor B::B modify the value when it is initialized, instead of when it is returned, you'll see the result you expect.

Getting the address of an rvalue

class MyClass {
public: MyClass(int a) : a(a) { }
int a;
};
#include <iostream>
void print(MyClass* a) { std::cout << a->a << std::endl; }
int main() {
print(&static_cast<MyClass&&>(MyClass(1337)));
return 0;
}
This doesn't work with GCC 4.6, while it used to work in a previous version.
Now it says: taking address of xvalue (rvalue reference).
Is there any way to securely pass the address of an rvalue to another function?
is: there is anyway to securely pass an rvalue reference (a.k.a. address of temporary) to another function without boringly storing it in a variable just to do that?
Yes, there is, like in the next example :
#include <iostream>
class MyClass {
public: MyClass(int a) : a(a) { }
int a;
};
void print(MyClass&& a) { std::cout << a.a << std::endl; }
int main() {
print( MyClass(1337) );
}
An rvalue does not necessarily have an address. However, there is a way to get the effect you want, by exploiting the fact that binding an rvalue to a reference forces it to be a temporary (which does have an address):
template<typename T> T *addressOfTemporary(T &&v) { return &v; }
Inside this function, v is an lvalue (despite being declared as T&&), so can have its address taken. You can use this function as follows:
class MyClass {
public: MyClass(int a) : a(a) { }
int a;
};
#include <iostream>
void print(MyClass* a) { std::cout << a->a << std::endl; }
int main() {
print(addressOfTemporary(MyClass(1337)));
return 0;
}
Note that the temporary's lifetime ends at the end of the full-expression (the print(...) expression, in this case), so you will need to be careful that the pointer is not used past that point.
If you don't particualrly need to print rvalues only, you can use a standard const reference instead:
class MyClass {
public: MyClass(int a) : a(a) { }
int a;
};
#include <iostream>
void print(const MyClass& a)
{ std::cout << a.a << std::endl; }
int main() {
print(MyClass(1337));
return 0;
}

Accessing and Altering Vectors through class references

This is the simplest I could work my problem down to, sorry about the length:
#include <vector>
#include <iostream>
class Bar
{
private:
std::vector<int> intVector_;
public:
Bar() {};
void addInt(int newInt)
{
intVector_.push_back(newInt);
std::cout << intVector_.size() << " ";
};
int getIntVectorSize() { return intVector_.size(); };
};
class Foo
{
private:
Bar bar_;
public:
Foo() { bar_ = Bar(); };
Bar getBar() { return bar_; };
};
int main(char argc, char* argv[])
{
Foo foo = Foo();
foo.getBar().addInt(1);
std::cout << foo.getBar().getIntVectorSize() << " ";
foo.getBar().addInt(2);
std::cout << foo.getBar().getIntVectorSize() << " ";
foo.getBar().addInt(3);
std::cout << foo.getBar().getIntVectorSize() << " ";
}
My problem is that adding an int to the vector only seems to last for the duration of addInt(). My output for the size of the vector looks like this:
1 0 1 0 1 0
I'm rather new to C++ and all this reference/pointer business, so I am stumped as to how I can fix this, or if this is even possible. Thanks for any help!
It's because getBar() returns a Bar by value, which makes a copy of bar_ for every call of the function, and you are modifying the vector of the temporary.
You can avoid this by returning a reference:
class Foo
{
private:
Bar bar_;
public:
Foo() { bar_ = Bar(); }; // you prob. want to use an initialiser list btw.
Bar& getBar() { return bar_; };
// ^ notice the ampersand
};
This way, any modifications done on the return value of getBar are done on bar_ and not a temporary copy that is destroyed at the end of the statement.