对象指针的向量,初始化

Vector of object pointers, initialisation

本文关键字:初始化 向量 指针 对象      更新时间:2023-10-16

我对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()) {
            // ...
        }
    }
    // ...
}

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

向量在首次初始化后不应更改。但是,我想我不能让它恒定,因为各种对象本身可能会在内部发生变化。我在常规数组上选择一个向量,因为我不想手动跟踪它的长度(事实证明容易出错)。

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

另外,我的印象是我必须手动delete使用new创建的任何内容,但它不会删除deletedelete[] ls。如果我尝试delete ls;编译器会抱怨"键入'类 std::vector<L*,std:::allocator><L*>>"参数给出给'删除',预期的指针"。

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

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

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

但是,我想我不能让它恒定,因为各种对象本身可能会在内部发生变化。

您仍然可以使向量本身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创建ls,只有它的元素。使用向量后,您必须delete其每个元素,但不是向量本身。

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

您确实必须在您创建的对象上使用删除。 您是在向量而不是对象上调用删除。 像这样:

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 ;
}

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

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

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