C++ 对象在被称为指向父类的指针时会丢失其成员的数据

C++ 对象在被称为指向父类的指针时会丢失其成员的数据,c++,c++11,lifetime,C++,C++11,Lifetime,此程序的输出缺少name和某些字符串的预期值 姓名:,年龄:4,某些字符串: 姓名:,年龄:3,某些字符串: 如果我在Source.cpp中为myVector的每个项目动态分配内存,那么它就正常了。我只是想知道为什么会这样,我犯了什么错误 值得注意的是,我使用Visual Studio 2015 C++编译器。 Parent.h #pragma once #include <string> class Parent { public: explicit Parent(st

此程序的输出缺少
name
某些字符串的预期值

姓名:,年龄:4,某些字符串:

姓名:,年龄:3,某些字符串:

如果我在
Source.cpp
中为
myVector
的每个项目动态分配内存,那么它就正常了。我只是想知道为什么会这样,我犯了什么错误

值得注意的是,我使用Visual Studio 2015 C++编译器。 Parent.h

#pragma once

#include <string>

class Parent
{
public:
    explicit Parent(std::string name, int age)
        : m_name(name), m_age(age) {};

    virtual const std::string toString() const
    {
        return "Name: " + m_name + ", Age: " + std::to_string(m_age);
    }

private:
    std::string m_name;
    int m_age;
};
#pragma once

#include "Parent.h"

class Child : public Parent
{
public:
    explicit Child(std::string name, int age, std::string someString)
        : Parent(name, age), m_someString(someString) {};

    virtual const std::string toString() const
    {
        return Parent::toString() + ", Some string: " + m_someString;
    }
private:
    std::string m_someString;
};
Source.cpp

#include <vector>
#include <iostream>

#include "Parent.h"
#include "Child.h"

int main()
{
    std::vector<Parent*> myVector;

    myVector.push_back(&Child("Foo", 4, "Test"));
    myVector.push_back(&Child("Bar", 3, "Test"));

    for (auto p : myVector)
    {
        std::cout << p->toString() << std::endl;
    }

    return 0;
}
#包括
#包括
#包括“Parent.h”
#包括“Child.h”
int main()
{
std::vector myVector;
myVector.push_back(&Child(“Foo”,4,“Test”);
myVector.push_back(&Child(“Bar”,3,“Test”));
用于(自动p:myVector)
{

std::cout toString()使用
std::vector myVector
;指针向量时,必须为对象分配内存:

   myVector.push_back( new Child("Foo", 4, "Test"));
要避免动态创建对象,请使用:

std::vector<Parent> myVector

   myVector.push_back(Child("Foo", 4, "Test"));
其功能是:

template <typename V>
void clearAndDestroy( std::vector<V*> *&myV)
{
    if(myV == NULL)
        return;

    std::set<V*> mySet;

    typename std::vector<V*>::iterator itr;
    typename std::set<V*>::iterator sitr;

    itr = myV->begin();
    while (itr != myV->end())
    {
        mySet.insert(*itr);
        ++itr;
    }

    sitr = mySet.begin();
    while (sitr != mySet.end())
    {
        delete(*sitr);
        ++sitr;
    }

    myV->clear(); // Removes all elements from the vector leaving the container with a size of 0.
}
模板
无效清除和销毁(标准::向量*&myV)
{
如果(myV==NULL)
返回;
std::设置mySet;
typename std::vector::迭代器itr;
typename std::set::迭代器sitr;
itr=myV->begin();
而(itr!=myV->end())
{
mySet.插入(*itr);
++itr;
}
sitr=mySet.begin();
while(sitr!=mySet.end())
{
删除(*sitr);
++sitr;
}
myV->clear();//从向量中删除大小为0的容器中的所有元素。
}
当你写

myVector.push_back(&Child("Foo", 4, "Test"));
创建类型为
Child
的临时对象,并将其指针保存在向量中

但它是一个临时对象,当
push_back()
结束时,它会立即被销毁;因此,向量中存储的指针值指向一个内存区域,该区域是空闲的,可能是可回收的

当您使用此指针时

std::cout << p->toString() << std::endl;
--编辑2--

正如Daniel Schepler(谢谢!)所指出的,使用

myV.emplace_back(new foo{"one"});
如果
myV
中的新元素导致向量内部内存的新分配,并且该分配失败,则会生成内存泄漏

这种情况不太可能发生,但也有可能发生,所以我认为最好避免这种风险(偏执狂是一种资产)

解决此问题的一种方法是在
emplace\u back()
之前调用
reserve()
,因此无需在
新建
之后重新分配内部内存

myV.reserve(2U); // or more
myV.emplace_back(new foo{"one"});
myV.emplace_back(new foo{"two"});
但是,为了解决这类问题,C++14引入了
std::make_unique
,因此在C++14中可以一起使用
push_back()
(但是这个示例需要一个
foo(std::string const&)
构造函数作为结构
foo


因此可以称为
std::unique_ptr
的移动构造函数,并且在重新分配向量失败的情况下,临时
std::unique_ptr
的析构函数释放分配的内存。

为什么
myVector.push_back(&Child(“Foo”,4,“Test”);
而不是
myVector.push_back(new Child(“Foo”,4,“Test”))
?是的,子对象的内存生命周期不会持续超出其使用的行。即,子对象构造。复制时添加对它的引用。子对象已破坏。列表包含已破坏的子对象引用。请考虑使用智能指针或复制构造函数,以便子对象继续存在于该行之外。有任何原因吗?T他的意思是我需要手动删除
myVector
中的条目,对吗?是的,但如果您不想删除,请使用std::vectormyVector@B.Lee不要使用
free
use
delete
@B.Lee关于智能指针的良好讨论:@B.Lee-答案改进。
myV.emplace\u back(新foo{“one”})
如果向量需要重新分配更多存储空间,但分配失败(并且一些调用方捕获了
错误分配
异常),则可能会发生内存泄漏。
myV.push_back(std::make_unique(“一”))
没有这个问题。如果扩展向量备份存储的分配失败,则
部署返回
返回,而不会从给定指针构造
唯一的ptr
。然而,如果将右值引用传递给现有的
唯一的ptr
,则堆栈展开将调用析构函数临时的,它释放内存,因为从未调用移动构造函数。
myV.emplace_back(new foo{"one"});
myV.reserve(2U); // or more
myV.emplace_back(new foo{"one"});
myV.emplace_back(new foo{"two"});
myV.push_back(std::make_unique<foo>("one"));
myV.push_back(std::make_unique<foo>("two"));
myV.push_back(std::unique_ptr<foo>{ new foo{"one"} });
myV.push_back(std::unique_ptr<foo>{ new foo{"two"} });