I'm getting some nasty segmentation faults through the g++ compiler on the following code. Any ideas on why this would happen and how to fix it would be great.
#include <iostream>
using namespace std;
class Base {
public:
Base() {}
virtual ~Base() {};
virtual int getNum(int) = 0;
};
class Derived: public Base {
public:
Derived() :
Base() {}
~Derived() {}
int getNum(int num) {
return num;
}
};
class Foo {
public:
Foo() {
};
void init() {
Derived n;
*baseId = n;
}
void otherStuff() {
cout << "The num is" << baseId->getNum(14) << baseId->getNum(15) << baseId->getNum(16) << baseId->getNum(15) << endl;
}
Derived* baseId;
};
int main() {
Foo f;
f.init();
f.otherStuff();
return 0;
}
Here:
void init() {
Derived n;
*baseId = n;
}
the pointer baseId is never initialised, resulting in undefined behaviour when you dereference it. It might be a good idea to explain what you are trying to do here. If you want to maintain a pointer to a Derived or a Base but which starts off pointing to a derived, you can say:
void init() {
baseId = new Derived;
}
but you will then probably need a copy constructor, an assignment operator and a destructor to manage the pointer.
Also, for several reasons, writing an init() function is not normally a good idea - you are better off doing the work directly in the constructor or its initialisation list.
When you call f.init(), the baseId member of Foo is not initialised, yet you dereference it in init(). Are you sure you don't want something more along the lines of:
baseId = new Derived()
void init() {
Derived n;
*baseId = n;
}
Apart from what Neil noted, derived n is local to your init function. It "dies" when you exit the function, so even if you assigned it correctly, it won't work.
What you want is not assigning on the stack but on the heap:
void init() {
baseId = new Derived();
}
or even better:
void init() {
delete baseId;
baseId = new Derived();
}
and a destructor and constructor pair to prevent problems :
Foo() : baseId(0) {};
~Foo() { delete baseId; }
If going for this method, be sure to either block copy constructor and assignment operator, or implement them properly. To implement them however, you'd need to implement copying of Derived too -- or best: use a safe shared_ptr to store the pointer.
Related
As the answers pointed out, this is a dumb mistake I made that has nothing to do with polymorphism or smart pointer. The corrected version is in the accepted answer.
============== Original question ==================
I am trying to make smart pointer work with polymorphism. In the following prototype code, the implementation for pure virtual function Base::print() should be in the memory block of Derived object. DerivedWrap have access to the pointer to the Derived object.
Why can not DerivedWrap::print() access the function implementation?
using namespace std;
class Base
{
public:
virtual void print() = 0;
};
class Derived : public Base
{
public:
Derived(int in) : i(in) {}
void print() {
cout << "int is " << i << endl;
}
private:
int i;
};
class DerivedWrap
{
public:
DerivedWrap() : DerivedWrap(make_unique<Derived>(2)) {}
DerivedWrap(unique_ptr<Base> pBase) : _pBase(move(pBase)) {}
void print()
{
_pBase->print();
}
private:
unique_ptr<Base> _pBase;
};
int main()
{
DerivedWrap pDW1();
pDW1->print(); // error: request for member ‘print’ in ‘pDW1’, which is of non-class type ‘DerivedWrap()’
DerivedWrap pDW2(make_unique<Derived>(2));
pDW2->print(); // error: base operand of ‘->’ has non-pointer type ‘DerivedWrap’
return 0;
}
You have a couple of issues.
This DerivedWrap pDW1(); is a function declaration whose return
type is DerivedWrap. It is not calling its default constructor which you are expecting to. You need simply
DerivedWrap pDW1; // calls the default constructor
// or
// DerivedWrap pDW1{};
Secondly, the pDW1 is simply a DerivedWrap object. Therefore, no need for calling operator->.
You need in short
DerivedWrap pDW1;
pDW1.print();
The same applies to the pDW2. You need
DerivedWrap pDW2(std::make_unique<Derived>(2));
pDW2.print();
Last but not the least, the Base must-have virtual destructor for the defined behaviour. See more:
When to use virtual destructors?
In short, you need
#include <iostream>
#include <memory>
class Base
{
public:
virtual void print() = 0;
virtual ~Base() = default; // provide virtual destructor
};
class Derived /*final*/: public Base
{
public:
// ... other code
void print() override // recommended to override the virtual functions
{
std::cout << "int is " << i << std::endl;
}
private:
int i;
};
class DerivedWrap /* final */
{
public:
// ...other code
void print()
{
_pBase->print();
}
private:
std::unique_ptr<Base> _pBase;
};
int main()
{
DerivedWrap pDW1; // or DerivedWrap pDW1{};
pDW1.print();
DerivedWrap pDW2{ std::make_unique<Derived>(2) };
pDW2.print();
}
As a side note, please do not practice with using namespace std;
You have some typos there, it should be:
int main()
{
DerivedWrap pDW1; // object instantiation, no () needed
pDW1.print(); //no dereferencing required
DerivedWrap pDW2(make_unique<Derived>(2));
pDW2.print(); // again, no dereference required
return 0;
}
One other note, for polymorphic objects you're going to need a virtual destructor in your base class.
This has nothing to do with polymorphism, virtual functions or smart pointers.
You just made two little typographical mistakes:
DerivedWrap pDW1(); declares a function. Remove the ().
-> dereferences pointers, but neither pDW1 nor pDW2 is a function. Use . instead.
when running the following code on MSVC 2013, x64 Debug config, it will show up a message box with this famous error message when quitting the main() function
"Run-Time Check Failure #2 - Stack around the variable 'tmp' was corrupted.".
The question I can't answer is: Why?
note that no error message will occur when running on Release config. (why?)
disclaimer: this is just a sample code, meaning that I'm trying to use this same design on other classes (one base and several derived) with much more methods and template arguments and with a much more complex data type than the basic int*.
#include <iostream>
template <class T>
class base {
public:
base() {
static_cast<T*>(this)->setData();
}
~base() {
static_cast<T*>(this)->destroyData();
}
void print() {
static_cast<T*>(this)->print_int();
}
};
class derived : public base<derived> {
public:
void setData() {
x = new int();
}
void destroyData() {
delete x;
x = nullptr;
}
void print_int() {
std::cout << "x = " << *x << std::endl;
}
private:
derived() {}
derived(const derived& other) {}
inline derived& operator= (derived copy) {}
int *x;
};
int main() {
base<derived> tmp;
tmp.print();
return 0;
}
EDIT:
#Yakk if I understand correctly, you propose as solution this code:
#include <iostream>
template <class T>
class mix_in : public T
{
public:
mix_in() { (this)->setData(); }
~mix_in() { (this)->destroyData(); }
void print() { (this)->print_int(); }
};
class foo
{
public:
void setData()
{
x = new int();
}
void destroyData()
{
delete x;
x = nullptr;
}
void print_int()
{
std::cout << "x = " << *x << std::endl;
}
foo() {}
private:
int *x;
};
int main()
{
mix_in<foo> tmp;
tmp.print();
return 0;
}
It works just fine, thank you. I'll probably use this pattern since it seems that there's no solution to use CRTP for what I'm trying to do.
But I still would like to understand why the stack corruption happens. In spite of all the discussion around use or not use CRTP for all things, I'd like to understand very precisely why it happens.
Thank you again.
As for your code shown in main():
int main() {
base<derived> tmp;
tmp.print();
return 0;
}
base<derived> tmp; that's wrong usage of this pattern, you wanted derived tmp;.
The point of the CRTP is that the derived class is injected to the base class and provides implementations for certain features that are resolved at compile time.
The base class is inherently intended, to be instantiated exclusively via inheritance. Thus you should ensure not to have any instantiations outside an inheritance context.
To avoid users of your implementation trapped by this misconception, make base's constructor(s) protected:
template <class T>
class base {
public:
~base() {
static_cast<T*>(this)->destroyData();
}
// ...
protected:
T* thisPtr;
base() : thisPtr(static_cast<T*>(this)) {
}
};
NOTE: The base class shouldn't call any methods dependent on the fully initialized derived class methods from within your base class constructor though, as you have shown with your sample (static_cast<T*>(this)->setData();)!
You may store the reference to T* for later use though, as shown in the above sample.
class derived : public base<derived> {
public:
derived() {
setData();
}
void destroyData() {
delete x;
x = nullptr;
}
void print_int() {
std::cout << "x = " << *x << std::endl;
}
private: // ????
derived(const derived& other) {}
inline derived& operator= (derived copy) {}
int *x;
};
Also it's a bit unclear, why you want to hide copy constructor and assignment operator for your class?
tmp is a base<derived>, not a derived. The point of CRTP is that the base class "knows" the object's actual type because it's being passed as the template parameter, but if you manually create a base<derived>, then the base class functions would think the object is a derived, but it isn't - it's just a base<derived>. Weird things (undefined behavior) happen as a result. (As noted in the other answer, you are also printing out something without setting it...)
As to your second question, the checks generated by MSVC to detect those sorts of programmer errors appears to be turned off in Release mode, presumably for performance reasons.
template <class T> class mix_in:public T {
public:
base() { (this)->setData(); }
~base() { (this)->destroyData(); }
void print() { (this)->print_int(); }
};
Rename derived to foo. Do not inherit from mix_in or base in foo.
Swap base for mix_in in main.
CRTP is not the solution to all problems.
You say in comments,
the derived class will never be instantiated, its constructor is never called
Others have already pointed out the undefined use of an unconstructed object. To be specific, consider that int *x is a derived member, and your base<derived> usage generates calls, in sequence, to derived::set_data(), derived::print_int(), and on exit derived::destroy_data(), all member functions of an object that doesn't exist, referring to a member for which you've never allocated space1.
But I think what you're after is wholly legitimate. Factoring code is the whole point of templates and inheritance, i.e. to make important code easier to even identify let alone comprehend, and any later refactoring easier to do, by abstracting out boilerplate.
So:
template < class T >
struct preconstruction_access_subset {}; // often left empty
template < class T, class S = preconstruction_access_subset<T> >
struct base : S {
base() { S::setData(); }
~base() { S::destroyData(); }
void print() { S::print_int(); }
};
// ... later ...
#include <iostream>
struct derived;
template<> struct preconstruction_access_subset<derived> {
// everything structors in `base<derived>` need
int *x;
void setData() { x = new int; }
void destroyData() { delete x; }
void print_int() { std::cout << x << '\n'; }
};
struct derived : base<derived> {
// everything no structors in any base class need to access
};
int main() {
base<derived> tmp;
tmp.print();
}
In this example print_int() isn't actually accessed during construction, so you could drop it back into the derived class and access it from `base as for "normal" CRTP, it's just a matter of what's clearest and best for your actual code.
1 That isn't the only problem, just the only one that's apparent without considering any reliance the compiler itself might need to place on the construction sequence. Think independent-name binding and potential inlining and the ways object identity morphs during {de,con}struction and compiler code factoring for all the potential template/inheritance/member-function/etc. combinations. Don't just hoist the int *x; to solve the current symptom, that would just kick the trouble farther down the road even if yours doesn't get that far yet.
Okay, so I'm experiencing some very weird issues with storing an array of base class pointers in a class then settings this base class pointers equal to some dynamically allocated derived class pointers.
My code is too long and bloated with GUI calls to post here, so I'll make some mock code here that demonstrates the methodology I'm using
Base Class - Base
class Base
{
public:
Base(){ // do nothing}
virtual void SetUI(){ // do nothing}
}
Derived Class - Derived
class Derived : public Base
{
public:
Derived() : Base() { // do nothing}
virtual void SetUI(){// do nothing}
}
This is a class that basically holds data for my program, it contains an array of pointers to the base class. These pointers are initialized by having them point to dynamically created objects of the derived class type.
class HelperClass
{
private:
Base * basearray[2];
public:
HelperClass()
{
basearray[0] = new Derived;
basearray[1] = new Derived;
}
Base * getBaseArray(int key)
{
return this->basearray[key];
}
}
here is my "main", this is where everything starts getting weird.
int main()
{
HelperClass hold;
hold.getBaseArray(0)->setUI();
// NOTHING HAPPENS ABOVE, THE CODE DOESN'T EVEN REACH THIS POINT, IT JUST GET'S LOST SOMEWHERE IN //THE ABOVE STATEMENT. i KNOW THIS BECAUSE I PUT AN exit(0) inside the function setUI() for both the //base and derived class and the program doesn't exit.
// this also does nothing
if(hold->getBaseArray(0) || !hold->getBaseArray(0))
exit(0);
return 0;
}
but oddly enough, if i do something like the following, where I just declare a base class pointer and have it point to a dynamically created object of the derived class, everything works just fine.
int main()
{
Base *hold;
hold = new Derived;
hold->setUI(); // <- this works polymorphically
return 0;
}
Does anyone have any idea why my program stops working when I try to work with the array of base class pointers inside the HelperClass? When I try to do getBaseArray(int) it doesn't return anything, which causes statements like
if(hold->getBaseArray(0) || !hold->getBaseArray(0)) {exit(0);}
to not make the program exit, which is weird because the pointer that getBaseArray() returns is either null or non-null, which means the program should exit no matter what
I (and my compiler) found two mistackes you have in the first main()
You declare SetUI() in your Base and Derived class, but in the main you try to call setUI(). Perhaps you have both functions in your project and that's why you recieved nothing.
You declare hold as an object and not a pointer. With this you can not do like hold->someFn(). You should call thet like hold.someFn().
Here is the code with corrections. It runs by me without problems. Try it.
struct Base
{
Base(){}
virtual ~Base() {}
virtual void SetUI() {
cout << "base" << endl;
}
};
struct Derived : public Base
{
Derived() : Base() {}
virtual ~Derived() {}
virtual void SetUI() {
cout << "derived" << endl;
}
};
class HelperClass
{
Base * basearray[2];
public:
HelperClass() {
basearray[0] = new Derived;
basearray[1] = new Derived;
}
~HelperClass() {
delete basearray[0];
delete basearray[1];
}
Base *getBaseArray(int key) {
return basearray[key];
}
};
int main()
{
HelperClass hold;
hold.getBaseArray(0)->SetUI();
if(hold.getBaseArray(0))
cout << "some output" << endl;
return 0;
}
Is it ok to delete an abstract class instead of a child? Will all allocs be deallocated thereby?
Consider a following situation as an example, but please do not limit your answers to that one case:
struct A {
virtual void fun() = 0;
};
struct B : public A {
void fun() { /* actually doing something here. */ }
};
struct C {
A *a;
void OneTask() {
// (...)
a = new B();
}
void AnotherTask() { /* using fun() in some way. */ }
~C() { delete a; }
};
The idea is to have multiple possible outcomes of OneTask() which result in an assignment of a pointer to different classes that inherit from A, B being just an example; and then to use such result reasonably in AnotherTask() and other methods of class C.
You must have virtual destructor in base class else complete destruction of derived class doesn't happen.
struct A {
virtual void fun() = 0;
virtual ~A()
{
}
};
Yes, it's perfectly fine to delete a without knowing what actual derived type a is pointing to.
As shivakumar pointed out, if you don't make your base class's destructor virtual, then deleting a derived class will not end up calling the base class's destructor. In your trivial example that's not a problem, but in real life you should always make your destructors virtual.
If A has a virtual destructor then both destructors of A and B are succesfully called (first B then A) ,
If you do not declare the constructor of A as virtual, then only the destructor of A is called during deletion and extended data of B may leak.
struct A {
virtual void fun() = 0;
virtual ~A();
};
struct B : public A {
void fun() { /* actually doing something here. */ }
~B();
};
Rewrote the question completely. Please, read it carefully
Single note to not confuse you: Base constructor expects pointer to constants array. It doesn't store a pointer itself, it stores the data!
I have the following code:
class Base {
public:
Base(int*);
// added this to explain why I need inheritance
virtual void abstractMethod() = 0;
};
Base::Base(const int *array) {
// just for example
cout << array[0] << endl;
cout << array[1] << endl;
cout << array[2] << endl;
}
class Derived : private Base {
public:
Derived();
void abstractMethod();
};
// who will delete? how to initialize?
Derived::Derived(): Base(new int[3]) {
}
I want to hide Base(int*) constructor from the user of my Derived class. To do that I need to supply default values to that array.
The problem is that when I use initialization list like this:
Derived::Derived(): Base(new int[3]) {
}
array is not initialized and Base constructor prints some garbage.
Another problem with this code: who will free that new array?
How to initialize array before it is passed to Base class?
Is it possible at all in C++?
Short answer: you can't (unless you are willing to rely on possible quirks in a particular compiler). For standard compliance, Base must be fully constructed before anything else in Derived can be safely touched.
Focus instead of what you are trying to achieve. Why must the array be in Derived; why do you feel a need to let Base initialize? There are probably dozens of safe ways of achieving what you need.
You can use static function to generate your objects:
class Base {
public:
Base(int*);
};
class Derived : Base {
public:
static Derived createDerived()
{
int *a= new int[3];
a[0]=a[1]=a[2]=1;
return Derived(a);
}
~Derived()
{
delete [] array;
}
private:
int *array;
Derived(int * a):arrary(a),Base(a)
{
}
};
That's some really bad design. Why would you need a constructor that takes an int* in your Base class, when there is no member to initialize?
Taken from your comment on Pontus' answer, it seems you are aware of that flaw.
class Base {
private:
int array[3];
public:
Base(int* arr);
virtual ~Base();
};
class Derived : Base {
public:
Derived();
};
You would then pass the array back to the base class using initialization lists:
Derived() : Base(new int[3]) {
array[0] = array[1] = array[2] = 1;
}
You basically call the constructor of class Base and pass the parameter.
And the constructor of Base would use an initialization list too:
Base(int* arr) : array(arr) {
}
Also, when the Derived constructor gets executed, the Base object is already fully initialized, that is promised by the standard.
Of course, you'd have to handle the destruction of your dynamically allocated array in Base:
virtual ~Base(){
delete [] array;
}
Cheers.
I came into another solution:
class Int3Array {
int array[3];
public:
Int3Array(int v1, int v2, int v3) {
array[0] = v1;
array[1] = v2;
array[2] = v3;
}
int* getPtr() {
return array;
}
};
Derived::Derived(): Base((Int3Array(1,1,1)).getPtr()) {
}
What do you think? Is it also bad?
The best solution I could find at this point is to use a static array:
class Derived : private Base {
public:
Derived();
void abstractMethod();
static int array[3];
};
int Derived::array[3] = {5, 5, 5};
Derived::Derived(): Base(array) {
}
Feel free to add your comments.
Found the solution:
Derived::Derived(): Base(new int[3]{1,1,1}) {
}
But alas, this is valid only in C++0x. g++ gives me a warning:
warning: extended initializer lists only available with -std=c++0x or -std=gnu++0x