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

Object slicing, vector element out of scope

本文关键字:范围 元素 切片 对象      更新时间:2023-10-16

我正在尝试在没有对象切片的情况下将派生类存储在向量中。我有一天中的大部分时间都在努力寻找,还没有弄清楚如何让它工作。我读过的解决方案建议存储指向派生对象的指针的实际对象。我无法让它工作,但我想添加这些对象以这样的方式向量,这将导致对象超出之前的范围矢量超出范围。所以,我认为这种解决方案不会奏效无论如何。另一种解决方案建议使基类抽象,但事实并非如此要么工作。我读到了覆盖赋值运算符和副本构造函数,但我认为他们最终没有做任何与正常不同的事情赋值运算符和 noraml 复制构造函数。我用虚拟的尝试过赋值运算符也没有成功。以下是我所经历的一个例子与之合作。main方法中的"vec.emplace_back(&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
}

您正在堆栈和 if 语句的作用域内创建对象,一旦它超出该作用域,该对象将不再存在,当 share_ptr 被超出 main 函数作用域的向量破坏时,您的程序将崩溃,因为它将尝试销毁不再存在的对象。

这:

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

我喜欢

std::vector<std::unique_ptr<CBaseEvent> > vec;

AngelCastillo经常使用的方法,但它只有一件事是错误的。

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

这可以通过任一方法修复

  • 添加虚拟析构函数或
  • 使用 std::shared_ptr ,这将类型信息保留在删除程序内部。

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