对象切片,矢量元素超出范围

时间:2013-07-14 21:33:29

标签: c++

我正在尝试将派生类存储在没有对象切片的向量中。我有 一天中的大部分时间都在努力寻找并且没有想出如何使它发挥作用。 我读过的解决方案建议存储指向派生对象的指针 实际的对象。我无法让它工作,但我想添加这些对象 以某种方式导向向量,这将导致对象超出范围之前 向量超出范围。所以,我认为这种解决方案不会起作用 无论如何。另一个解决方案建议将基类抽象,但事实并非如此 工作要么。我读到了重写赋值运算符和副本 构造函数,但我不认为他们最终做了与正常情况不同的事情 赋值运算符和noraml拷贝构造函数。我用虚拟试了一下 赋值运算符也没有成功。以下是我的一个例子 与...合作。 “vec.emplace_back(& derivedEvent);”主要方法中的陈述 导致基类被添加到向量中。紧接着, 对象超出范围,向量不再包含derivedEvent的数据。我 编程仍然很新,所以我尝试的任何东西都可能做错了。

#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
}

2 个答案:

答案 0 :(得分:1)

您正在堆栈中和if语句的范围内创建对象,一旦它超出该范围,对象将不再存在,并且当share_ptr被超出范围的向量销毁时您的程序将崩溃的主要功能,因为它将尝试销毁不再存在的对象。

这样:

 if (true) {
        CDerivedEvent derivedEvent = CDerivedEvent("1", "2", "3");
        vec.emplace_back(&derivedEvent);
    }

应该是:

 if (true) {
        CDerivedEvent* derivedEvent = new CDerivedEvent("1", "2", "3");
        vec.emplace_back(derivedEvent);
    }

它应该按照您的预期工作,但正如Jhon Purdy在下面的评论中所说,这将更合适:

int main()
{
    std::vector<std::unique_ptr<CBaseEvent> > vec;

    vec.push_back(std::unique_ptr<CBaseEvent>(new CDerivedEvent("1", "2", "3")));

    return 0; 
}

答案 1 :(得分:1)

我喜欢

std::vector<std::unique_ptr<CBaseEvent> > vec;
AngelCastillo使用的方法很多,但是它只有一个问题。

std::unique_ptr<CBaseEvent>(new CDerivedEvent(blah))将导致通过CDerivedEvent类型的指针删除类型为CBaseEvent*的对象。由于CBaseEvent没有虚拟析构函数(它甚至不是多态的),因此这是未定义的行为。

这可以通过

解决
  • 添加虚拟析构函数 或
  • 使用std::shared_ptr,它在删除器内部保留类型信息。

    std::vector<std::shared_ptr<CBaseEvent> > vec;
    vec.push_back(std::make_shared<CDerivedEvent>(whatever));