我有一个基类,以及它的一些变形。我希望能够创建类型为base的对象,然后将其变换为派生类,并返回到base。可以这样做吗?我这样做,但我不确定这是正确的方法:
假设我有这些课程:
class base {
public:
int var;
base();
virtual ~base();
virtual void func1();
void func2();
}
class derived1 : base {
public:
unique_ptr<otherClass> otherVar;
vector<unique_ptr<anotherClass>> myVec;
derived1();
~ derived1() {
otherVar.reset();
for (unsigned int i=0; i< myVec.size(); i++) {
myVec[i].reset();
}
myVec.clear();
vector<unique_ptr< anotherClass >>().swap(myVec);
}
void func1(){
//do something
}
}
class derived2 : base {
public:
derived2();
~ derived2();
void func1(){
//do something else
}
}
现在代码中的其他地方我这样做:
unique_ptr<base> myObject;
myObject = unique_ptr< derived1 > (new derived1());
如果以后我这样做:
myObject.reset();
myObject = unique_ptr< base > (new base());
堆内存显着增加。是什么原因,以及如何避免这个问题?
EDIT1
我为derived1添加了更多细节。 我没有错误,程序运行没有问题,只有内存在myObject变形时上升。 顺便说一句,myObject永远不会超出范围,它只会改变它的形状(所以我不确定我使用的是正确的指针)。
EDIT2
我设法摆脱了类中的大多数指针(遗憾的是我无法在所有情况下都使用普通变量),现在我的内存增长非常少。 但我的理解是,使用智能指针应该让生活更轻松而不是更难。我们可以使用C ++中的任何类型的指针,释放内存而不删除它(我认为reset()应该这样做)然后再重新分配一些其他值吗?
我必须说,对于简单的对象,这可以通过unique_ptr来完成,但对于复杂的类(其他类指针作为其成员变量),似乎即使在调用reset之后,某些内存也永远不会被释放( )。
EDIT3
我发现问题不在于代码的C ++部分,而在于OpenGL部分。很抱歉这里的专家很困惑XD。
我这样做的时候:
otherVar.reset();
此otherVar包含OpenGL纹理。这个对象的析构函数应该一次删除所有纹理(至少在Mac上):
glDeleteTextures(textureCount, textures);
但是在iOS(OpenGL ES)上,我不得不单独删除纹理,如下所示:
glDeleteTextures(1, &tex.textureID);
尽管如此,我还不知道为什么glDeleteTextures(textureCount,textures)在iOS应用中不会立即删除所有纹理,但至少我找到了一种解决方法。
谢谢大家。
答案 0 :(得分:0)
无法确定,但我怀疑代码中可能存在循环所有权模式。以下是一个简单示例中的内容:
#include <iostream>
#include <memory>
struct B;
struct C;
struct A
{
std::unique_ptr<B> b_ptr_;
~A();
};
struct B
{
std::unique_ptr<C> c_ptr_;
~B();
};
struct C
{
std::unique_ptr<A> a_ptr_;
~C();
};
A::~A()
{
std::cout << "~A()\n";
}
B::~B()
{
std::cout << "~B()\n";
}
C::~C()
{
std::cout << "~C()\n";
}
int
main()
{
std::unique_ptr<A> a_ptr(new A);
a_ptr->b_ptr_ = std::unique_ptr<B>(new B);
a_ptr->b_ptr_->c_ptr_ = std::unique_ptr<C>(new C);
a_ptr->b_ptr_->c_ptr_->a_ptr_ = std::move(a_ptr);
}
编译运行时,该程序没有输出。这是令人担忧的,因为A
,B
和C
的析构函数未运行,表明内存泄漏。
有许多方法可以解决循环所有权问题。但第一步是了解你的内存所有权图,并确保它是非循环的,并且使用unique_ptr
,还必须确保图中的任何节点只有一个(拥有)父节点。
以下是打破此示例所有权周期的一种方法:
#include <iostream>
#include <memory>
struct B;
struct C;
struct A
{
std::unique_ptr<B> b_ptr_;
~A();
};
struct B
{
std::unique_ptr<C> c_ptr_;
~B();
};
struct C
{
A* a_ptr_;
~C();
};
A::~A()
{
std::cout << "~A()\n";
}
B::~B()
{
std::cout << "~B()\n";
}
C::~C()
{
std::cout << "~C()\n";
}
int
main()
{
std::unique_ptr<A> a_ptr(new A);
a_ptr->b_ptr_ = std::unique_ptr<B>(new B);
a_ptr->b_ptr_->c_ptr_ = std::unique_ptr<C>(new C);
a_ptr->b_ptr_->c_ptr_->a_ptr_ = a_ptr.get();
}
正确输出:
~A()
~B()
~C()
即。插入一个非拥有的&#34;原始指针&#34;进入循环。也可以使用shared_ptr
和weak_ptr
打破周期:
#include <iostream>
#include <memory>
struct B;
struct C;
struct A
{
std::shared_ptr<B> b_ptr_;
~A();
};
struct B
{
std::shared_ptr<C> c_ptr_;
~B();
};
struct C
{
std::weak_ptr<A> a_ptr_;
~C();
};
A::~A()
{
std::cout << "~A()\n";
}
B::~B()
{
std::cout << "~B()\n";
}
C::~C()
{
std::cout << "~C()\n";
}
int
main()
{
std::shared_ptr<A> a_ptr(new A);
a_ptr->b_ptr_ = std::shared_ptr<B>(new B);
a_ptr->b_ptr_->c_ptr_ = std::shared_ptr<C>(new C);
a_ptr->b_ptr_->c_ptr_->a_ptr_ = std::move(a_ptr);
}
~A()
~B()
~C()
如果我认为循环所有权是您案件的罪魁祸首,那么通过审核,理解和记录代码中的所有权路径,您的时间就不会完全被浪费。