我的 std::vector 应该包含指针还是结构?

发布于 2024-12-01 18:10:05 字数 554 浏览 0 评论 0原文

我知道保存指针会产生额外的取消引用操作的开销,但它可以节省我的时间,包括包含结构定义的(可能很大)头文件。

然而,我的偏好是由具有 std::vector的优点来确定。 *ptr2Vect 成员。即,不必对每个元素调用删除。这有多大的性能优势呢? Vector真的可以在堆栈上分配对象吗?我对模板类相当陌生,想知道动态数组是否可以在堆栈上扩展,价格是多少?

_编辑_

我无法理解默认的复制构造函数和operator=成员,并且试图将事物保留为简单的结构。我没有明确定义实现,因此担心将向量元素设置为对象而不是指针会在赋值时创建临时对象,该对象将被破坏,从而破坏其副本。

_编辑_

很抱歉延迟提供相关信息(我对我的代码感到害羞)。

我想调用push_back(newObj)。现在,如果我不使用指针,我就会遇到一个大问题,因为我不想执行深层复制,但我的 dtor 将释放复制构造函数调用的 LHS 和 RHS 共享的内存。

I know that holding pointers incurs the overhead of an extra dereference operation but it saves me including the (potentially large) header file that contains the definition of my struct.

However my preference is to be determined by the advantage of having a std::vector<myStruct> *ptr2Vect member. Namely, not having to call delete on each element. How big a performance advantage is this? Can vector really allocate objects on the stack? I am fairly new to template classes and wonder if it could be possible for a dynamic array to expand on the stack and at what price?

_EDIT_

I fail in understanding default copy constructor and operator= members and am trying to keep things as simplistic structs. I have neither implementation defined explicitly so fear that making the vector element an object instead of pointer will create temporary object at assignment time that will be destructed and so ruin its copy.

_EDIT_

Sorry for the delay in delivering pertinent information (I am shy with my code).

I want to call push_back(newObj). Now if I don't use pointers I have a big problem in that I don't want to perform a deep copy but my dtor will free up the memory shared by the LHS and RHS of this invocation of the copy constructor.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

錯遇了你 2024-12-08 18:10:05

作为一般经验法则,我会说您可能不想将指针放入容器中,除非有充分的理由。

考虑指针的可能原因:

  • 您有虚拟函数
  • 您有类层次结构
  • 您不知道使用它们的对象的大小。 (在这种情况下你只能使用指针或引用,并且不能有引用向量)
  • 你的对象非常大(可能对此进行基准测试)

不将指针放入容器中的最大原因是它使它更容易避免犯错误和意外泄漏内存。当您开始考虑例外情况时尤其如此。

容器中没有指针可以更轻松地使用 STL ,请考虑:

#include <vector>
#include <string>
#include <iostream>
#include <iterator>
#include <algorithm>

int main() {
  std::vector<std::string> test;
  test.push_back("hello world");
  std::copy(test.begin(), test.end(), 
            std::ostream_iterator<std::string>(std::cout, "\n"));
}

对比:(

#include <vector>
#include <string>
#include <iostream>
#include <iterator>
#include <algorithm>

int main() {
  std::vector<std::string*> test;
  // if push_back throws then this will leak:
  test.push_back(new std::string("hello world"));
  // Can't do:
  std::copy(test.begin(), test.end(), 
            std::ostream_iterator<std::string>(std::cout, "\n"));
  // Will now leak too
}

永远不会这样做)

或者可能:

#include <vector>
#include <string>
#include <iostream>
#include <iterator>
#include <algorithm>

int main() {
  std::vector<std::string*> test;
  std::string str("hello world");
  test.push_back(&str);
  // Can't do:
  std::copy(test.begin(), test.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
}

但是这一点让我感到不舒服——完全不清楚代码中其他地方的删除会是一件非常糟糕的事情,而且即使没有泄漏问题,你仍然不能非常舒服地使用STL算法。

As a general rule of thumb I'd say you probably don't want to put pointers in your containers, unless there's a good reason.

Possible reasons to consider pointers:

  • You have virtual functions
  • You have a class hierarchy
  • You don't know the size of the objects where you're using them this. (You can only use pointers or references in that case and you can't have a vector of references)
  • Your objects are exceedingly large (probably benchmark this)

The biggest reason not to put pointers in containers would be that it makes it much easier not to make a mistake and accidentally leak memory. This is especially true when you start to consider exceptions.

Not having pointers in your containers makes it much easier to use STL <algorithms>, consider:

#include <vector>
#include <string>
#include <iostream>
#include <iterator>
#include <algorithm>

int main() {
  std::vector<std::string> test;
  test.push_back("hello world");
  std::copy(test.begin(), test.end(), 
            std::ostream_iterator<std::string>(std::cout, "\n"));
}

Versus:

#include <vector>
#include <string>
#include <iostream>
#include <iterator>
#include <algorithm>

int main() {
  std::vector<std::string*> test;
  // if push_back throws then this will leak:
  test.push_back(new std::string("hello world"));
  // Can't do:
  std::copy(test.begin(), test.end(), 
            std::ostream_iterator<std::string>(std::cout, "\n"));
  // Will now leak too
}

(which I would never do)

Or possibly:

#include <vector>
#include <string>
#include <iostream>
#include <iterator>
#include <algorithm>

int main() {
  std::vector<std::string*> test;
  std::string str("hello world");
  test.push_back(&str);
  // Can't do:
  std::copy(test.begin(), test.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
}

But the semantics of this one make me feel uncomfortable - it's not clear at all that delete elsewhere in the code would be a very bad thing and you still can't use STL algorithms very comfortably even if there is no leak issue.

ぃ弥猫深巷。 2024-12-08 18:10:05

指针取消引用的“开销”基本上为零。也就是说,与在其位置引用对象相比,您将很难测量它。谨防早期优化和过度优化,这是所有编程罪恶的根源。

您应该选择对应用最有意义的方式(指针或对象)。

The "overhead" of a pointer dereference is essentially zero. That is, you would have great difficulty of measuring that versus referencing an object in its place. Beware of early optimization and over-optimization, the root of all programming evil.

You should do whichever (pointer or object) makes the most application sense.

软的没边 2024-12-08 18:10:05

首先,我同意那些说要以最有意义的方式编写代码的人的观点,并且不要担心这样的微观优化,直到您的分析工具告诉您这样做。

也就是说,您应该更多地担心访问您的数据,而不是分配和释放数据。如果对向量元素的访问模式具有良好的局部性(例如,循环遍历所有元素,或一起访问附近的元素),那么指针向量可能会破坏该局部性并对性能造成重大影响。

当然,对速度的首要关注是使用好的算法。但第二个问题是拥有良好的局部性,因为内存速度很慢……而且相对于 CPU,它每年都会变慢。

因此,对于小型、简单的对象,vector 几乎肯定会比 vector 更快,而且可能快很多 更快。

至于“向量真的可以在堆栈上分配对象吗”,从语义角度来看,答案是肯定的,但从实现角度来看,答案是否定的(最有可能)。典型的向量实现在内部由三个指针组成:Base、Current 和 End。所有三个都指向堆上的连续块,向量的析构函数将释放该块。 (同样,这是一个典型的实现;理论上,您的编译器和/或运行时可能会做其他事情。但我打赌它不会。)

这样的实现通过重新分配该块和复制数据来支持动态扩展。这并不像听起来那么慢,原因有两个:(1)线性内存访问(例如复制)非常快; (2) 每次重新分配都会将块的大小增加一个因子,这意味着 push_back 仍然是 O(1) 摊销。

First, I agree with those who say to write your code however it makes the most sense, and do not worry about micro-optimizations like this until your profiling tool tells you to.

That said, you should be worried more about accessing your data, not allocating and freeing it. If your access patterns to vector elements have good locality -- e.g., looping through them all, or accessing nearby elements together -- then a vector of pointers is likely to destroy that locality and cause a major hit to performance.

The #1 concern for speed is using good algorithms, of course. But the #2 concern is having good locality, because memory is slow... And relative to the CPU, it gets slower every year.

So, for small, simple objects, vector<Obj> is almost certainly going to be faster than vector<Obj *>, and possibly much faster.

As for "can a vector really allocate objects on the stack", the answer is yes in terms of semantics, but no in terms of implementation (most likely). A typical vector implementation consists of three pointers internally: Base, Current, and End. All three point into a contiguous block on the heap, and the vector's destructor will deallocate that block. (Again, this is a typical implementation; in theory, your compiler and/or runtime might do something else. But I bet it doesn't.)

Such an implementation supports dynamic expansion by re-allocating that block and copying data. This is not as slow as it sounds for two reasons: (1) Linear memory access (e.g. copying) is pretty fast; and (2) each reallocation increases the size of the block by a factor, which means push_back is still O(1) amortized.

跨年 2024-12-08 18:10:05

针对指针与结构体没有提到的一件事是内存的连续性(在嵌入式方面更重要)。基本上,结构体向量将分配在 1 个内存块中,而指向结构体的指针向量(可能)将分配在整个位置。内存和数据缓存的碎片将因此受到严重影响。

The one thing not mentioned against pointers vs structs is continuity of memory (matters more on embedded). Basically, a vector of struct will be allocated in 1 block of memory while a vector of pointers to struct will (probably) be allocated all over the place. Fragmentation of memory and Data Cache will thus seriously suffer.

苦妄 2024-12-08 18:10:05

你的问题不是很清楚。首先讨论指针向量,然后编写如下内容: std::vector*ptr2Vect

  1. std::vector; *ptr2Vect 是一个myStruct 对象指向向量的指针。该向量不存储指针,因此您无需担心所持有对象的内存管理 - 只需确保 myStruct 是可复制构造的。您确实需要手动管理指向向量的指针的清理(ptr2Vect
  2. 大多数现代系统都可以非常有效地使用指针,如果您问此类问题,那么您正在遵循该路线对于过早的优化,停下来,退一步。
  3. vector 依赖于动态分配,但是它如何扩展,它进行管理(你可以在一定程度上控制它,例如,如果你事先知道大小,你可以 reserve

从我从问题中收集到的信息来看,您确实还没有到需要担心自动/动态分配和指针取消引用的开销的地步。这些是你最不关心的,只要学会编写好的代码 - 所有其他的东西都会稍后出现(如果有必要的话)

Your question is not very clear. First you talk of a vector of pointers, and then you write something like: std::vector<myStruct> *ptr2Vect.

  1. std::vector<myStruct> *ptr2Vect is a pointer to a vector of myStruct objects. The vector is not storing pointers, so you don't need to worry about memory management of the obects held - just need to ensure that myStruct is copy constructable. You do need to manually manage the clean up of the pointer to the vector though (ptr2Vect)
  2. Most modern systems work very efficiently with pointers, if you are asking this kind of question, you're following the route for premature optimization, stop, take a step back.
  3. vector relies on dynamic allocation, but how it expands, it manages (you can control it to an extent, for example, if you know the size before hand, you can reserve)

From what I gather from the question, you're really not at the point where you need to worry about the overhead of automatic/dynamic allocation and pointer de-referencing. These are the least of your concerns, just learn to write good code - all that other stuff will come later (if at all necessary)

陪你搞怪i 2024-12-08 18:10:05

但是,我的偏好是由拥有 std::vector *ptr2Vect 成员的优势来确定。 Namey,不必对每个元素调用删除。这有多大的性能优势?

这取决于元素的数量,但它可以为您节省大量的内存和时间。请参阅:

继承的成本是多少?

向量真的可以在堆栈上分配对象吗?

是的。向量可以为此目的保留内部分配,或者编译器可以在某些情况下对此进行优化。这不是您应该依赖的功能/优化。您可以根据您的需求创建自己的分配器或 pod 数组容器。

我对模板类相当陌生,想知道动态数组是否可以在堆栈上扩展以及以什么价格?

如果大小恒定,那么特定的实现(例如boost::array)可以节省大量的运行时开销。我已经为不同的上下文编写了几种类型。

However my preference is to be determined by the advantage of having a std::vector *ptr2Vect member. Namey, not having to call delete on each element. How big a performance advantage is this?

it depends on the number of elements, but it can save you a ton of memory and time. see:

What is the cost of inheritance?

Can vector really allocate objects on the stack?

yes. a vector could reserve an internal allocation for this purpose, or the compiler could optimize this in some cases. that's not a feature/optimization you should rely on. you could create your own allocator or pod-array container tailored for your needs.

I am fairly new to template classes and wonder if it could be possible for a dynamic array to expand on the stack and at what price?

if you have a constant size, then a specific implementation (such as boost::array) can save a ton of runtime overhead. i've written several types for different contexts.

无声无音无过去 2024-12-08 18:10:05

我给你的第一个建议是,“你不必将指向向量的指针”作为成员。你想要一个简单的
向量 myVector; OR向量<我的向量;

其次,您将根据以下问题做出决定:

  1. 向量的大小是多少? (最多有多少个元素)
    说 n
  2. struct 的大小是多少? (尺寸(T))
    说 s
  3. 复制该结构的成本是多少?
    说 c
  4. 你的结构持有一些资源吗? (例如一些文件句柄或信号量等)?
    如果它持有一些资源,那么向量会让你的生活变得更加复杂。

现在 n,s,c 将确定向量的运行时开销
对于向量,n、s、c 造成的成本为零。
对于向量,由于 n,s,c 导致的成本为 n*s sizeUnits + n*cexecutionUnits。

我自己的经验法则:不存在经验法则。首先用向量编码,如果它不够好,然后用向量

如果你的程序是一个小程序,在你使用你的向量后将退出进程,那么我什至不会费心去释放它们。
如果没有,那么只需运行
for(auto it=v.begin();it!=v.end();++it) 删除 *it;

My first suggestion to you would , 'you dont have to have pointer-to-vector' as member. You want a simple
vector myVector; OR vector< myVector;

Secondly, you will make your decision based on following questions

  1. What is the size of vector ? (how many elements max)
    say n
  2. What is the size of struct ? (sizeof(T))
    say s
  3. What is the cost of copying the struct ?
    say c
  4. Is your struct holding some resource ? (e.g. some file handle or semaphore et cetra) ?
    If it is holding some resource, then vector can complicate your life much more.

Now n,s,c are going to determine your runtime overhead of vector
For vector, cost due to n,s,c are zero.
For vector, cost due to n,s,c are n*s sizeUnits + n*c executionUnits.

My own rule of thumb : No rule of thumb exists. First code it with vector, if it is not good enough, then go with vector

If your program, is a small program which is going to exit the process after you have used your vector, then I wouldnt even bother to free them.
IF NOT, then just run a
for(auto it=v.begin();it!=v.end();++it) delete *it;

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文