Reputation: 3
I'm trying to store a derived class in a vector without object slicing. I've been looking hard for most of the day and haven't figured out how to make it work. Solutions I've read about suggest storing pointers to the derived objects instead of the actual objects. I couldn't get that to work, but I want to add these objects to a vector in such a way which will result in the objects going out of scope before the vector goes out of scope. So, I don't think that kind of solution will work anyway. Another solution suggests making the base class abstract but that didn't work either. I read about overriding the assignment operator and the copy constructor but I don't think they ended up doing anything different from the normal assignment operator and the noraml copy constructor. I tried that with a virtual assignment operator too with no success. Below is an example of what I have been working with. The "vec.emplace_back(&derivedEvent);" statement in the main method results in the base class being added to the vector. Immediately afterward, the object goes out of scope and the vector no longer contains derivedEvent's data. I'm still quite new to programming so anything I tried may have been done incorrectly.
#include <string>
#include <vector>
////////////////////////////////////////////////////////////////////////////////
class CBaseEvent {
protected:
CBaseEvent(){}
std::string m_strBeginning;
std::string m_strEnd;
public:
CBaseEvent(std::string strBeginning, std::string strEnd)
: m_strBeginning(strBeginning), m_strEnd(strEnd){}
};
////////////////////////////////////////////////////////////////////////////////
class CDerivedEvent : public CBaseEvent {
private:
CDerivedEvent(){}
std::string m_strMiddle;
public:
CDerivedEvent(
std::string strBeginning,
std::string strMiddle,
std::string strEnd)
: CBaseEvent(strBeginning, strEnd),
m_strMiddle(strMiddle){}
};
////////////////////////////////////////////////////////////////////////////////
int main() {
std::vector<std::shared_ptr<CBaseEvent>> vec;
if (true) {
CDerivedEvent derivedEvent = CDerivedEvent("1", "2", "3");
vec.emplace_back(&derivedEvent);
}
return 0; //CRASH: possible corruption of the heap
}
Upvotes: 0
Views: 507
Reputation: 283664
I like the
std::vector<std::unique_ptr<CBaseEvent> > vec;
approach used by AngelCastillo a whole lot, but there's just one thing wrong with it.
std::unique_ptr<CBaseEvent>(new CDerivedEvent(blah))
will result in deleting an object of type CDerivedEvent
via pointer of type CBaseEvent*
. Since CBaseEvent
doesn't have a virtual destructor (it is not even polymorphic), this is undefined behavior.
This can be fixed by either
using std::shared_ptr
, which preserves the type information internally inside the deleter.
std::vector<std::shared_ptr<CBaseEvent> > vec;
vec.push_back(std::make_shared<CDerivedEvent>(whatever));
Upvotes: 1
Reputation: 2435
You are creating the object in the stack and inside the scope of the if statement, once it goes out of that scope the object will no longer exist, and when the share_ptr is destroyed by the vector going out of the scope of the main function your program will crash since it will attempt to destroy an object that no longer exists.
this:
if (true) {
CDerivedEvent derivedEvent = CDerivedEvent("1", "2", "3");
vec.emplace_back(&derivedEvent);
}
Should be:
if (true) {
CDerivedEvent* derivedEvent = new CDerivedEvent("1", "2", "3");
vec.emplace_back(derivedEvent);
}
It should work as you expect, but as Jhon Purdy said in the comment below, this would be more appropiate:
int main()
{
std::vector<std::unique_ptr<CBaseEvent> > vec;
vec.push_back(std::unique_ptr<CBaseEvent>(new CDerivedEvent("1", "2", "3")));
return 0;
}
Upvotes: 1