3

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

我有一些像下面这样的代码。L是一个抽象类(它有许多纯虚函数),并且A,BC都是从 . 派生的常规类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,但它不会ls使用delete或删除delete[]。如果我尝试delete ls;编译器会抱怨“type 'class std::vector<L*, std::allocator<L*> >' argument given to 'delete', expected pointer”。

以上是安全的还是会导致一些内存问题?

4

4 回答 4

4

但确实必须有更好的方法来初始化该向量。对?

我不这么认为,至少在没有 C++0x 的情况下不会。你更喜欢哪种方式?您的初始化代码完全没问题。

但是,我认为我不能将其设为 const,因为各种对象本身可能会在内部发生变化。

您仍然可以制作向量本身const,只有它的成员类型不能是指向constthen 的指针。

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

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

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 创建的任何内容,但它不会使用 delete 或 delete[] 删除 ls。

你的印象是正确的,但你没有ls用创造new,只有它的元素。使用向量后,您必须对它的delete每个元素,而不是向量本身。

保存多态指针的 STL 容器的推荐替代方法是Boost 指针容器库

于 2011-05-09T18:28:55.657 回答
1

您确实必须对您创建的对象使用 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 ;
}
于 2011-05-09T18:22:05.350 回答
0

如果 C++11 是可以接受的,那么最好使用 astd::array而不是std::vector

std::array<L *, 3> = {new A(), new B(), new C()};
于 2011-05-09T18:46:18.860 回答
0

由于您在编译时知道大小,因此我建议使用 aarray而不是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>(),
} };

现代编译器在标准库中发布了他们自己的array版本shared_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>(),
} };
于 2011-05-09T18:50:51.670 回答