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
usedelete
@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"} });