C++ 对象向量与指向对象的指针向量

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6624819/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 20:26:40  来源:igfitidea点击:

C++ vector of objects vs. vector of pointers to objects

c++pointersvector

提问by Alan

I am writing an application using openFrameworks, but my question is not specific to just oF; rather, it is a general question about C++ vectors in general.

我正在使用 openFrameworks 编写应用程序,但我的问题不仅仅针对 oF;相反,这是一个关于 C++ 向量的一般问题。

I wanted to create a class that contains multiple instances of another class, but also provides an intuitive interface for interacting with those objects. Internally, my class used a vector of the class, but when I tried to manipulate an object using vector.at(), the program would compile but not work properly (in my case, it would not display a video).

我想创建一个包含另一个类的多个实例的类,但也提供了一个直观的界面来与这些对象进行交互。在内部,我的类使用了类的向量,但是当我尝试使用 vector.at() 操作对象时,程序会编译但无法正常工作(在我的情况下,它不会显示视频)。

// instantiate object dynamically, do something, then append to vector
vector<ofVideoPlayer> videos;
ofVideoPlayer *video = new ofVideoPlayer;
video->loadMovie(filename);
videos.push_back(*video);

// access object in vector and do something; compiles but does not work properly
// without going into specific openFrameworks details, the problem was that the video would
// not draw to screen
videos.at(0)->draw();

Somewhere, it was suggested that I make a vector of pointers to objects of that class instead of a vector of those objects themselves. I implemented this and indeed it worked like a charm.

在某处,有人建议我制作一个指向该类对象的指针向量,而不是这些对象本身的向量。我实现了这个,确实它就像一个魅力。

vector<ofVideoPlayer*> videos;
ofVideoPlayer * video = new ofVideoPlayer;
video->loadMovie(filename);
videos.push_back(video);
// now dereference pointer to object and call draw
videos.at(0)->draw();

I was allocating memory for the objects dynamically, i.e. ofVideoPlayer = new ofVideoPlayer;

我正在为对象动态分配内存,即 ofVideoPlayer = new ofVideoPlayer;

My question is simple: why did using a vector of pointers work, and when would you create a vector of objects versus a vector of pointers to those objects?

我的问题很简单:为什么使用指针向量有效,何时创建对象向量与指向这些对象的指针向量?

采纳答案by Klaim

My question is simple: why did using a vector of pointers work, and when would you create a vector of objects versus a vector of pointers to those objects?

我的问题很简单:为什么使用指针向量有效,何时创建对象向量与指向这些对象的指针向量?

std::vectoris like a raw array allocated with new and reallocated when you try to push in more elements than its current size.

std::vector就像当您尝试推入比当前大小更多的元素时分配了 new 和重新分配的原始数组。

So, if it contains Apointers, it's like if you were manipulating an array of A*. When it needs to resize (you push_back()an element while it's already filled to its current capacity), it will create another A*array and copy in the array of A*from the previous vector.

所以,如果它包含A指针,就像你在操作一个A*. 当它需要调整大小时(你的push_back()一个元素已经被填充到当前容量),它会创建另一个A*数组并A*从前一个向量的数组中复制。

If it contains Aobjects, then it's like you were manipulating an array of A, so Ashould be default-constructible if there are automatic reallocations occuring. In this case, the whole Aobjects get copied too in another array.

如果它包含A对象,那么就像您在操作 的数组一样A,因此A如果发生自动重新分配,则应该是默认构造的。在这种情况下,整个A对象也被复制到另一个数组中。

See the difference? The Aobjects in std::vector<A>can change address if you do some manipulations that requires the resizing of the internal array.That's where most problems with containing objects in std::vectorcomes from.

看到不同?如果您执行一些需要调整内部数组大小的操作,则 中A对象std::vector<A>可以更改地址。这就是包含对象的大多数问题的std::vector来源。

A way to use std::vectorwithout having such problems is to allocate a large enough array from the start. The keyword here is "capacity".The std::vectorcapacity is the realsize of the memory buffer in which it will put the objects. So, to setup the capacity, you have two choices:

一种std::vector不会出现此类问题的使用方法是从一开始就分配一个足够大的数组。这里的关键词是“容量”。std::vector容量是真正的内存缓冲区中,它将把对象的大小。因此,要设置容量,您有两种选择:

1) size your std::vectoron construction to build all the object from the start , with maximum number of objects - that will call constructors of each objects.

1)std::vector调整构建大小以从一开始就构建所有对象,最大数量的对象 - 这将调用每个对象的构造函数。

2) once the std::vectoris constructed (but has nothing in it), use its reserve()function: the vector will then allocate a large enough buffer (you provide the maximum size of the vector). The vectorwill set the capacity. If you push_back()objects in this vector or resize()under the limit of the size you've provided in the reserve()call, it will never reallocate the internal buffer and your objects will not change location in memory, making pointers to those objects always valid (some assertions to check that change of capacity never occurs is an excellent practice).

2)一旦std::vector构建(但没有任何内容),使用它的reserve()功能:向量将分配一个足够大的缓冲区(您提供向量的最大大小)。向量将设置容量。如果您push_back()在此向量中的对象或resize()在您在reserve()调用中提供的大小限制下,它将永远不会重新分配内部缓冲区并且您的对象不会更改内存中的位置,从而使指向这些对象的指针始终有效(要检查的一些断言永远不会发生容量变化是一种极好的做法)。

回答by Tuxer

What you have to know about vectors in c++ is that they have to use the copy operator of the class of your objects to be able to enter them into the vector. If you had memory allocation in these objects that was automatically deallocated when the destructor was called, that could explain your problems: your object was copied into the vector then destroyed.

关于 C++ 中的向量,您必须了解的是,它们必须使用对象类的复制运算符才能将它们输入到向量中。如果您在调用析构函数时自动释放这些对象中的内存分配,则可以解释您的问题:您的对象被复制到向量中然后被销毁。

If you have, in your object class, a pointer that points towards a buffer allocated, a copy of this object will point towards the same buffer (if you use the default copy operator). If the destructor deallocates the buffer, when the copy destructor will be called, the original buffer will be deallocated, therefore your data won't be available anymore.

如果您的对象类中有一个指向已分配缓冲区的指针,则该对象的副本将指向同一个缓冲区(如果您使用默认复制运算符)。如果析构函数释放缓冲区,当调用复制析构函数时,原始缓冲区将被释放,因此您的数据将不再可用。

This problem doesn't happen if you use pointers, because you control the life of your elements via new/destroy, and the vector functions only copy pointer towards your elements.

如果您使用指针,则不会发生此问题,因为您通过 new/destroy 控制元素的生命周期,而向量函数仅将指针复制到您的元素。

回答by Zhehao Mao

If you are allocating memory for the objects using new, you are allocating it on the heap. In this case, you should use pointers. However, in C++, the convention is generally to create all objects on the stack and pass copies of those objects around instead of passing pointers to objects on the heap.

如果使用 为对象分配内存,则new是在堆上分配内存。在这种情况下,您应该使用指针。但是,在 C++ 中,约定通常是在堆栈上创建所有对象并传递这些对象的副本,而不是将指针传递给堆上的对象。

Why is this better? It is because C++ does not have garbage collection, so memory for objects on the heap will not be reclaimed unless you specifically deletethe object. However, objects on the stack are always destroyed when they leave scope. If you create objects on the stack instead of the heap, you minimize your risk of memory leaks.

为什么这样更好?这是因为 C++ 没有垃圾收集,因此除非您专门delete指定对象,否则不会回收堆上对象的内存。但是,堆栈上的对象在离开作用域时总是会被销毁。如果您在堆栈而不是堆上创建对象,则可以最大限度地降低内存泄漏的风险。

If you do use the stack instead of the heap, you will need to write good copy constructors and destructors. Badly written copy constructors or destructors can lead to either memory leaks or double frees.

如果确实使用堆栈而不是堆,则需要编写良好的复制构造函数和析构函数。写得不好的复制构造函数或析构函数可能导致内存泄漏或双重释放。

If your objects are too large to be efficiently copied, then it is acceptable to use pointers. However, you should use reference-counting smart pointers (either the C++0x auto_ptr or one the Boost library pointers) to avoid memory leaks.

如果您的对象太大而无法有效复制,那么使用指针是可以接受的。但是,您应该使用引用计数智能指针(C++0x auto_ptr 或 Boost 库指针之一)以避免内存泄漏。

回答by Steve Townsend

vectoraddition and internal housekeeping use copies of the original object - if taking a copy is very expensive or impossible, then using a pointer is preferable.

vector添加和内部管理使用原始对象的副本 - 如果获取副本非常昂贵或不可能,那么最好使用指针。

If you make the vectormember a pointer, use a smart pointerto simplify your code and minimize the risk of leaks.

如果您将vector成员设为指针,请使用智能指针来简化您的代码并将泄漏风险降至最低。

Maybe your class does not do proper (ie. deep) copy construction/assignment? If so, pointers would work but not object instances as the vector member.

也许您的班级没有进行适当的(即深的)复制构造/分配?如果是这样,指针将起作用,但不能作为向量成员使用对象实例。

回答by Naszta

Usually I don't store classes directly in std::vector. The reason is simple: you would not know if the class is derived or not.

通常我不直接将类存储在std::vector. 原因很简单:您不知道该类是否是派生的。

E.g.:

例如:

In headers:

在标题中:

class base
{
public:
  virtual base * clone() { new base(*this); };
  virtual ~base(){};
};
class derived : public base
{
public:
  virtual base * clone() { new derived(*this); };
};
void some_code(void);
void work_on_some_class( base &_arg );

In source:

在来源:

void some_code(void)
{
  ...
  derived instance;
  work_on_some_class(derived instance);
  ...
}

void work_on_some_class( base &_arg )
{
  vector<base> store;
  ...
  store.push_back(*_arg.clone());
  // Issue!
  // get derived * from clone -> the size of the object would greater than size of base
}

So I prefer to use shared_ptr:

所以我更喜欢使用shared_ptr

void work_on_some_class( base &_arg )
{
  vector<shared_ptr<base> > store;
  ...
  store.push_back(_arg.clone());
  // no issue :)
}

回答by Jman

The main idea of using vector is to store objects in a continue space, when using pointer or smart pointer that won't happen

使用 vector 的主要思想是将对象存储在一个继续空间中,当使用不会发生的指针或智能指针时