对象指针传染媒介,初始化

时间:2011-05-09 18:14:17

标签: c++ stdvector

我对C ++还不是很有经验,所以如果这是基本的东西,请耐心等待。

我有一些类似下面的代码。 L是一个抽象类(它有许多纯虚函数),ABC是从L派生的常规类。可能有这些中的任何一个,它们都是不同的。

int main() {
    // ...

    std::vector<L*> ls(3) ; 

    ls[0] = new A ;
    ls[1] = new B ;
    ls[2] = new C ;

    int i ;
    for (i = 0 ; i < ls.size() ; i++) {
        if (ls[i]->h()) {
            // ...
        }
    }

    // ...
}

它有效,但必须有一个更好的方法来初始化该向量。正确?

第一次初始化后,矢量不应该改变。我认为我不能使它成为const,因为各种对象本身可能会发生变化。我在常规数组上选择了一个向量,因为我不想手动跟踪它的长度(这证明容易出错)。

理想情况下,我想将矢量的定义和初始化从main中拉出来,最好是一个单独的文件,然后我可以#include。当我尝试编译器抱怨它“在'='标记之前”期望构造函数,析构函数或类型转换“。所有类ABC都有默认构造函数。

另外,我的印象是我必须手动delete使用new创建的任何内容,但不会删除lsdelete或{delete[] 1}}。如果我尝试delete ls;,编译器会抱怨“类型'类std :: vector&lt; L *,std :: allocator&lt; L *&gt;&gt;'参数赋予'delete',期望指针”。

以上是否安全或是否会导致内存问题?

4 个答案:

答案 0 :(得分:4)

  

但是必须有一种更好的方法来初始化该向量。正确?

我不这么认为,至少没有C ++ 0x。你更喜欢哪种方式?你的初始化代码完全正常。

  

我认为我不能使它成为const,因为各种对象本身可能会在内部发生变化。

你仍然可以使向量本身const,只有它的成员类型不能成为const的指针。

  

我在常规数组上选择了一个向量,因为我不想手动跟踪它的长度(证明容易出错)。

您不必跟踪常量数组中的长度:

L* ls[] = { new A, new B, new C };
// with <boost/range/size.hpp>
std::size_t num = boost::size(ls);
// without Boost, more error-prone
// std::size_t num = sizeof ls / sizeof ls[0];

通常你不需要大小,例如与Boost.Range。

  

理想情况下,我想将矢量的定义和初始化从main中拉出来,最好是一个单独的文件然后我可以#include。

这会违反单一定义规则。您可以将声明放入头文件中,但定义必须放入源文件中。

  

另外,我的印象是我必须手动删除使用new创建的任何内容,但不会删除ls,删除或删除[]。

您的展示是正确的,但您尚未使用ls创建new,仅创建元素。使用向量后,您必须delete每个元素,而不是向量本身。

持有多态指针的STL容器的推荐替代方法是Boost pointer container library

答案 1 :(得分:1)

您确实必须对您创建的对象使用delete。您在向量上调用delete而不是对象。类似的东西:

for(size_t i = 0; i < ls.size(); i++){
    delete ls[i];
}

对于构造问题,您可以将它们包装到函数中,并将该函数放入其自己的头文件中。您还必须确保包含所有相关的类头文件。

void init_vector(std::vector<LS*> & v){
    ls[0] = new A ; 
    ls[1] = new B ;
    ls[2] = new C ;
}

答案 2 :(得分:0)

如果C ++ 11可以接受,那么使用std::array代替std::vector可能会更好:

std::array<L *, 3> = {new A(), new B(), new C()};

答案 3 :(得分:0)

由于你知道编译时的大小,我建议使用array而不是vector。使用类模板array而不是C样式数组可以获得标准容器接口的好处,就像vector一样。也就是说,您可以在数组上调用size()并获取迭代器等等。

为了确保你不会忘记delete对象,我建议使用智能指针:

#include <boost/array.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>

boost::array<boost::shared_ptr<L>, 3> ls = { {
    boost::make_shared<A>(),
    boost::make_shared<B>(),
    boost::make_shared<C>(),
} };

现代编译器在标准库中发布了自己的arrayshared_ptr版本:

#include <array>
#include <memory>

std::array<std::shared_ptr<L>, 3> ls = { {
    std::make_shared<A>(),
    std::make_shared<B>(),
    std::make_shared<C>(),
} };

请注意,技术上不需要最外面的大括号,但是将它们排除可能会产生编译器警告,至少在我的编译器上会发生这种情况。

  

理想情况下,我想将矢量的定义和初始化从main中拉出来,最好是一个单独的文件然后#include

在这种情况下,您需要一个包含声明的头文件和一个定义 ls的实现文件:

// file ls.h

#ifndef LS_H
#define LS_H

#include <boost/array.hpp>
#include <boost/shared_ptr.hpp>

extern boost::array<boost::shared_ptr<L>, 3> ls;

#endif

// file ls.cpp

#include "ls.h"
#include <boost/make_shared.hpp>

boost::array<boost::shared_ptr<L>, 3> ls = { {
    boost::make_shared<A>(),
    boost::make_shared<B>(),
    boost::make_shared<C>(),
} };