[英]Object loses data of its members when referred to as pointer to parent class
This program's output is missing the intended values for name
and Some string
. 该程序的输出缺少name
和Some string
的预期值。
Name: , Age: 4, Some string: 名称:,年龄:4,某些字符串:
Name: , Age: 3, Some string: 名称:,年龄:3,一些字符串:
If I dynamically allocate memory for each item for myVector
in Source.cpp
then it works out okay. 如果我动态为每个项目分配内存myVector
在Source.cpp
那么好的作品出来。 I'm just wondering why this works out as it does, and what mistakes I have made. 我只是想知道为什么会这样,以及我犯了什么错误。
Worth noting is I'm using Visual Studio 2015 C++ compiler. 值得注意的是我正在使用Visual Studio 2015 C ++编译器。
Parent.h 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;
};
Child.h Child.h
#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 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;
}
When you write 当你写
myVector.push_back(&Child("Foo", 4, "Test"));
you create a temporary object of type Child
and save its pointer in the vector. 您将创建一个类型为Child
的临时对象,并将其指针保存在向量中。
But it's a temporary object that is immediately destroyed when push_back()
ends; 但这是一个临时对象,当push_back()
结束时会立即销毁; so the value of the pointer memorized in the vector point to an area of memory that is free and, probably, recycled. 因此,存储在向量中的指针值指向的内存区域是空闲的,并且有可能被回收了。
When you use this pointer 使用此指针时
std::cout << p->toString() << std::endl;
the behavior is undefined. 行为是不确定的。
Is different when you allocate the memory of the object because the object isn't destroyed immediately after the push_back()
call and the object is still available when you call toString()
[but remember to call delete
, at the end, or (better) use smart pointers]. 分配对象的内存时有所不同,因为在push_back()
调用之后该对象并没有立即被销毁,并且在调用toString()
时该对象仍然可用[但是请记住在最后调用delete
,或者(更好)使用智能指针]。
-- EDIT -- -编辑-
You ask for 你要
care to add how smart pointers fit in this problem 小心添加智能指针如何解决此问题
so I show a simple simplified example using std::unique_ptr
. 因此,我展示了一个使用std::unique_ptr
的简单示例。
Observe that you have to use emplace_back()
instead of push_back()
; 注意您必须使用emplace_back()
而不是push_back()
; this is because the isn't a copy constructor (for evident reasons) for std::unique_ptr
[anyway, I suggest to use emplace_back()
, when possible, instead push_back()
]. 这是因为它不是std::unique_ptr
的副本构造函数(出于明显的原因)[无论如何,我建议尽可能使用emplace_back()
,而不是push_back()
]。
#include <vector>
#include <memory>
#include <iostream>
struct foo
{ std::string str; };
int main ()
{
std::vector<std::unique_ptr<foo>> myV;
myV.emplace_back(new foo{"one"});
myV.emplace_back(new foo{"two"});
for ( auto const & p : myV )
std::cout << p->str << std::endl;
return 0;
}
-- EDIT 2 -- -编辑2-
As pointed by Daniel Schepler (thanks!), adding values in the std::vector
with 正如Daniel Schepler所指出的(谢谢!),在std::vector
添加以下值std::vector
myV.emplace_back(new foo{"one"});
can generate a memory leak in case the new element in myV
cause a new allocation of the internal memory of the vector and this allocation fail. 万一myV
的新元素导致向量内部存储器的新分配而该分配失败,则可能会产生内存泄漏。
It's an unlikely case but it's possible so I think it's better to avoid the risk (the paranoia is an asset). 这种情况不太可能发生,但是有可能,所以我认为最好避免这种风险(妄想症是一种资产)。
A way to solve this problem is call reserve()
before emplace_back()
, so there is no need to reallocate the internal memory after the new
解决此问题的一种方法是在emplace_back()
reserve()
之前调用reserve()
,因此无需在new
内存之后重新分配内部内存。
myV.reserve(2U); // or more
myV.emplace_back(new foo{"one"});
myV.emplace_back(new foo{"two"});
but, to solve this sort of problem, C++14 introduced std::make_unique
, so in C++14 can be used together push_back()
(but this example require a foo(std::string const &)
constructor for the struct foo
) 但是,为解决此类问题,C ++ 14引入了std::make_unique
,因此在C ++ 14中可以将push_back()
一起使用(但此示例要求foo(std::string const &)
构造函数用于struct foo
)
myV.push_back(std::make_unique<foo>("one"));
myV.push_back(std::make_unique<foo>("two"));
Another way, also for C++11, is moving in myV
a temporary std::unique_ptr
同样对于C ++ 11,另一种方法是在myV
移动临时std::unique_ptr
myV.push_back(std::unique_ptr<foo>{ new foo{"one"} });
myV.push_back(std::unique_ptr<foo>{ new foo{"two"} });
so can be called the move constructor of std::unique_ptr
and, in case of failure reallocating the vector, the destructor of the temporary std::unique_ptr
free the allocated memory. 因此可以称为std::unique_ptr
的move构造函数,并且在重新分配向量失败的情况下,临时std::unique_ptr
的析构函数将释放已分配的内存。
When you use std::vector<Parent*> myVector
; 当您使用std::vector<Parent*> myVector
; vector of pointers you have to allocate memory for the object: 您必须为对象分配内存的指针向量:
myVector.push_back( new Child("Foo", 4, "Test"));
To avoid dynamic creation of objects use: 为避免动态创建对象,请使用:
std::vector<Parent> myVector
myVector.push_back(Child("Foo", 4, "Test"));
Since you are asking how to get rid of the allocated objects this is a suggestion below: 由于您正在询问如何摆脱分配的对象,因此以下建议:
clearAndDestroy(&myVector);
And the function is: 函数是:
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.
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.