混合在堆和堆栈上创建的矢量对象

时间:2013-02-08 13:55:56

标签: c++ heap new-operator

我有一个相当简单的问题,但无法解决它。

考虑一下我有这段代码:

#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)中存在内存泄漏,如果我不使用此方法创建的数组元素调用delete。

我怎么说,std :: vector的哪些元素已经在堆上创建,所以我可以在~A()析构函数中释放内存,如下所示:

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

我是否必须删除通过临时新操作调用创建的向量元素?

我可能在这里看不到一些非常简单的东西,但我的应用程序中确实需要这个功能。

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

2 个答案:

答案 0 :(得分:3)

幸运的是,这一行不会编译:

ptA->Set(B(10));

这是因为B(10)是一个构造函数转换表达式,它创建一个B类型的prvalue临时表; prvalue无法绑定到B &的左值参考void A::Set(B& ptb)参数。这是C ++语言,可以保护您免受将悬空指针存储到临时值的后果。

A按值存储B项通常更有意义:

std::vector<B> Bs;

答案 1 :(得分:2)

您应该决定是否将B类型的对象的所有权授予A的实例。混合两者不会带来任何好处。想象一下记录这个类:this class may or may not take ownership to the objects it holds.

我不推荐的替代方法是创建指向B的指针的包装器,它在其构造函数中获取指向B的指针和布尔标志,并且布尔标志将指示指针是否指向对象在堆栈上或堆上的对象上分配。