矢量<X*> vec vs 矢量<X>* vec

vector<X*> vec vs vector<X>* vec

本文关键字:gt vec 矢量 lt vs      更新时间:2023-10-16
以下

两者之间的内存使用量有什么区别:

std::vector<X*> vec

其中每个元素都在堆上,但向量本身不在

std::vector<X>* vec

其中向量在堆上声明,但每个元素都是(在堆栈上?

第二个选项没有多大意义 - 这是否意味着矢量指针在堆上,但它指向堆栈上的每个元素?

std::vector<X*> vec

是 X 类的指针数组。例如,在创建不可复制的类/对象数组(如 C++98 中的 std::fstream )时,这很有用。所以

std::vector<std::fstream> vec;

是错误的,并且不起作用。但

std::vector<std::fstream*> vec;

工作,同时您必须为每个元素创建一个新对象,因此例如,如果您想要 5 个 fstream 元素,您必须编写类似的东西

vec.resize(5);
for(unsigned long i = 0; i < vec.size(); i++)
{
    vec[i] = new std::fstream;
}

当然,根据您的应用,还有许多其他用途。

现在第二种情况是向量本身的指针。所以:

vector<int>* vec;

只是一个指针! 它不携带任何信息,除非你为向量本身创建对象,否则你不能使用它,比如

vec = new vector<int>();

最终,您可以将其用作:

vec->resize(5);

现在这并不真正有用,因为向量无论如何都会将它们数据存储在堆上并管理它们携带的内存。因此,只有在您有充分理由时才使用它,有时您会需要它。我没有任何关于它如何有用的例子。

如果这是你真正问的:

vector<X>* vec = new vector<X>();

这意味着整个向量及其所有元素都在堆上。这些元素占用堆上的连续内存块。

区别在于您需要在哪里(以及做什么)进行手动内存管理。

每当C++中有一个原始的 C 样式指针时,你需要做一些手动内存管理 - 原始指针可以指向任何东西,编译器不会为你做任何自动构造或破坏。 因此,您需要了解指针指向的位置以及谁"拥有"其余代码中指向的内存。

所以当你有

std::vector<X*> vec;

您无需担心向量本身的内存管理(编译器将为您完成),但您确实需要担心指向X对象的内存管理,以便您放入向量中的指针。 如果要使用new分配它们,则需要确保在某些时候手动delete它们。

当你有

std::vector<X> *vec;

确实需要担心矢量本身的内存管理,但您不需要担心单个元素的内存管理。

最简单的是,如果您有:

std::vector<X> vec;

然后你根本不需要担心内存管理 - 编译器会为你处理它。

在使用良好的现代C++风格的代码中,以上都不是真的

std::vector<X*>X 类型对象或其任何子类的句柄集合,您不拥有这些子类。 所有者知道它们是如何分配的,并且会解除它们的分配 - 你不知道也不在乎

在实践中,std::vector<X>*只会用作函数参数,该参数表示您不拥有的向量(调用者拥有),但您将对其进行修改。 根据一种常见的方法,它是指针而不是矢量的事实意味着它是可选的。 更罕见的是,它可能被用作类成员,其中已知附加向量的生存期比指向它的类的寿命长。

std::vector<std::unique_ptr<X>> 是各种X子类(可能直接X自身)的混合对象的多态集合。 有时,如果移动成本很高X您可能会非多态地使用它,但现代风格使大多数类型移动起来很便宜。

在 C++11 之前,std::vector<some_smart_pointer<X> >(是的,右括号之间有一个空格)将用于多态大小写和不可复制大小写。 请注意,some_smart_pointer不是std::unique_ptr,当时还不存在,std::auto_ptr ,这在集合中不可用。 boost::unique_ptr是一个不错的选择。 在 C++11 中,集合元素的可复制性要求放宽为可移动性,因此这个原因完全消失了。(还有一些类型既不可复制也不可移动,例如 ScopeGuard 模式,但无论如何都不应存储在集合中)

相关文章: