2013-02-08 69 views
1

我有一个相当简单的问题,但无法将其包裹在头上。在堆和堆栈上创建混合矢量对象

考虑我有这样的代码:

#include <iostream> 
#include <vector> 
using namespace std; 

class B 
{ 
public: 
    B(const int& val) {this->val = val;} 
    int val; 
}; 

class A 
{ 
public: 
    A() {} 
    void Set(B& ptb) 
    { 
     ptBs.push_back(&ptb); 
    } 
    void Set(const int& val) 
    { 
     ptBs.push_back(new B(val)); 
    } 
    std::vector<B*> ptBs; 
}; 

int main() 
{ 
    A* ptA = new A(); 
    ptA->Set(B(10)); 
    ptA->Set(38); 

    for (int i=0; i<ptA->ptBs.size(); i++) 
     cout << ptA->ptBs[i]->val << endl; 

    delete ptA; 

    system("pause"); 
    return 0; 
} 

输出结果是:

10 
38 

但我认为有内存泄漏是怎么回事在void Set(const int& val),如果我不会打电话与数组中删除元素,由此方法创建。

我怎么能说,这的std ::向量已经在堆上创建的元素,所以我可以在〜A()析构函数像这样释放内存:

~A() 
{ 
    for (int i=0; i<ptBs.size(); i++) 
     delete ptBs[i]; 
} 

,做我必须删除矢量元素,是否通过临时性的新操作呼叫创建?

也许我在这里看不到很简单的东西,但我真的需要在我的应用程序中使用此功能。

PS。 10和38只是一个简单的例子。使用不同的参数可以调用数千次函数来调用函数Set

+0

这不是一个解构,它的析构函数。 – bash0r 2013-02-08 13:57:16

+0

你可以使用'std :: pair '来表示哪些元素是堆分配的。在析构函数中,您可以执行'if(ptBs [i] .first)delete ptBs [i] .second;' – bash0r 2013-02-08 14:00:52

+1

让您的生活变得简单 - 选择一个或另一个。 – 2013-02-08 14:18:00

回答

3

幸运的是,这条线将不编译:

ptA->Set(B(10)); 

这是因为B(10)是它创建了一个prvalue临时B类型的构造转换表达式;一个前值不能绑定到左值引用B &参数void A::Set(B& ptb)。这是C++语言保护您免受将悬挂指针存储为临时值的后果。

通常更有意义的A按值来存储它的B项目:

std::vector<B> Bs; 
+0

那么我提供的代码是完全正常工作和编译。但是,我决定将对象存储在数组中,而不是指针。谢谢。 – GuardianX 2013-02-08 16:39:39

2

您应该决定是否将B类型的对象的所有权转让给A的实例。混合使用不会导致任何问题。试想一下,记录这个类:this class may or may not take ownership to the objects it holds.

,我不建议另一种方法是创建一个包装,以指针B,这需要一个指向B和一个布尔标志在它的构造函数和布尔标志将指示指针是分配给栈上的对象还是分配给堆上的对象。