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?
然而,我的偏好是由具有std::vector
_EDIT_
_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.
我没能理解默认的复制构造函数和操作符=成员,我试图把事情保持为简单的结构。我没有明确的实现定义,所以害怕让vector元素成为对象而不是指针会在分配时创建临时对象,这会被破坏,从而破坏它的副本。
_EDIT_
_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.
我想调用push_back(newObj)。如果我不使用指针,我有一个大问题,我不想做一个深入的复制,但我的dtor将释放LHS和RHS对复制构造函数的调用共享的内存。
7 个解决方案
#1
7
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:
如果容器中没有指针,那么使用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"));
}
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.
但是这个代码的语义让我感到不舒服——不清楚删除代码中的其他部分会是一件很糟糕的事情,而且即使没有泄漏问题,你仍然不能很舒服地使用STL算法。
#2
3
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.
你应该做任何(指针或对象)最有应用价值的事情。
#3
3
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.
当然,对速度的首要关注是使用好的算法。但是第二个问题是有好的局部性,因为记忆是缓慢的……相对于CPU,它每年都变慢。
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.
这种实现通过重新分配块和复制数据来支持动态扩展。这并不像听起来那么慢,有两个原因:(1)线性内存访问(例如复制)非常快;(2)每次重新分配都会使块的大小增加一个因数,这意味着push_back仍然是O(1)平摊。
#4
2
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.
指针和结构之间没有提到的一点是内存的连续性(在嵌入式中更重要)。基本上,一个struct的向量将被分配到一个内存块中,而一个指向struct的指针(可能)将被分配到整个位置。因此,内存和数据缓存的碎片化将严重受损。
#5
1
Your question is not very clear. First you talk of a vector of pointers, and then you write something like: std::vector<myStruct> *ptr2Vect
.
你的问题不太清楚。首先讨论指针的向量,然后写出如下内容:std::vector
-
std::vector<myStruct> *ptr2Vect
is a pointer to a vector ofmyStruct
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 thatmyStruct
is copy constructable. You do need to manually manage the clean up of the pointer to the vector though (ptr2Vect
) -
向量
*ptr2Vect是指向myStruct对象的向量的指针。向量不存储指针,所以您不需要担心所持有的obect的内存管理——只需确保myStruct是copy构造函数即可。您确实需要手动管理指向向量的指针的清理(ptr2Vect) - 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.
- 大多数现代系统都非常有效地使用指针,如果你问的是这样的问题,那么你是在遵循提前优化的路线,停下来,后退一步。
-
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 canreserve
) - vector依赖于动态分配,但是它如何扩展,它管理(例如,如果您事先知道大小,您可以控制它)
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)
我从这个问题中得出的结论是,您确实不需要担心自动/动态分配和指针去引用的开销。这些都是你最不关心的,只要学会写好代码就行了——所有其他的东西都会在以后出现(如果有必要的话)
#6
0
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?
但是我的偏好是由拥有std::vector *ptr2Vect成员的优势决定的。Namey,不用在每个元素上调用delete。性能优势有多大?
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.
如果您有一个常量大小,那么特定的实现(例如boost:::array)可以节省大量的运行时开销。我已经为不同的上下文编写了几种类型。
#7
0
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;
我给你的第一个建议是,‘你不需要有point -to-vector’作为会员。你需要一个简单的向量myVector;或向量< myVector;
Secondly, you will make your decision based on following questions
第二,你将根据以下问题做出决定
- What is the size of vector ? (how many elements max) say n
- 向量的大小是多少?(最多多少个元素)n
- What is the size of struct ? (sizeof(T)) say s
- 结构体的尺寸是多少?(sizeof(T))说
- What is the cost of copying the struct ? say c
- 复制结构体的成本是多少?说c
- 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.
- 你的结构体有资源吗?(例如一些文件句柄或信号量和cetra) ?如果它持有一些资源,那么向量会使你的生活更加复杂。
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.
现在n s c将会决定向量的运行时开销,因为n s c是0。对于向量,n s c的代价是n*s大小单位+ n*c执行单位。
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;
如果你的程序是一个小程序,它会在你使用了你的向量之后退出这个过程,那么我甚至不会费事去释放它们。如果不是,那么就运行for(auto it=v.b ubegin ();it!= v.d ude();+ it)删除*它;
#1
7
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:
如果容器中没有指针,那么使用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"));
}
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.
但是这个代码的语义让我感到不舒服——不清楚删除代码中的其他部分会是一件很糟糕的事情,而且即使没有泄漏问题,你仍然不能很舒服地使用STL算法。
#2
3
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.
你应该做任何(指针或对象)最有应用价值的事情。
#3
3
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.
当然,对速度的首要关注是使用好的算法。但是第二个问题是有好的局部性,因为记忆是缓慢的……相对于CPU,它每年都变慢。
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.
这种实现通过重新分配块和复制数据来支持动态扩展。这并不像听起来那么慢,有两个原因:(1)线性内存访问(例如复制)非常快;(2)每次重新分配都会使块的大小增加一个因数,这意味着push_back仍然是O(1)平摊。
#4
2
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.
指针和结构之间没有提到的一点是内存的连续性(在嵌入式中更重要)。基本上,一个struct的向量将被分配到一个内存块中,而一个指向struct的指针(可能)将被分配到整个位置。因此,内存和数据缓存的碎片化将严重受损。
#5
1
Your question is not very clear. First you talk of a vector of pointers, and then you write something like: std::vector<myStruct> *ptr2Vect
.
你的问题不太清楚。首先讨论指针的向量,然后写出如下内容:std::vector
-
std::vector<myStruct> *ptr2Vect
is a pointer to a vector ofmyStruct
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 thatmyStruct
is copy constructable. You do need to manually manage the clean up of the pointer to the vector though (ptr2Vect
) -
向量
*ptr2Vect是指向myStruct对象的向量的指针。向量不存储指针,所以您不需要担心所持有的obect的内存管理——只需确保myStruct是copy构造函数即可。您确实需要手动管理指向向量的指针的清理(ptr2Vect) - 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.
- 大多数现代系统都非常有效地使用指针,如果你问的是这样的问题,那么你是在遵循提前优化的路线,停下来,后退一步。
-
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 canreserve
) - vector依赖于动态分配,但是它如何扩展,它管理(例如,如果您事先知道大小,您可以控制它)
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)
我从这个问题中得出的结论是,您确实不需要担心自动/动态分配和指针去引用的开销。这些都是你最不关心的,只要学会写好代码就行了——所有其他的东西都会在以后出现(如果有必要的话)
#6
0
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?
但是我的偏好是由拥有std::vector *ptr2Vect成员的优势决定的。Namey,不用在每个元素上调用delete。性能优势有多大?
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.
如果您有一个常量大小,那么特定的实现(例如boost:::array)可以节省大量的运行时开销。我已经为不同的上下文编写了几种类型。
#7
0
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;
我给你的第一个建议是,‘你不需要有point -to-vector’作为会员。你需要一个简单的向量myVector;或向量< myVector;
Secondly, you will make your decision based on following questions
第二,你将根据以下问题做出决定
- What is the size of vector ? (how many elements max) say n
- 向量的大小是多少?(最多多少个元素)n
- What is the size of struct ? (sizeof(T)) say s
- 结构体的尺寸是多少?(sizeof(T))说
- What is the cost of copying the struct ? say c
- 复制结构体的成本是多少?说c
- 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.
- 你的结构体有资源吗?(例如一些文件句柄或信号量和cetra) ?如果它持有一些资源,那么向量会使你的生活更加复杂。
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.
现在n s c将会决定向量的运行时开销,因为n s c是0。对于向量,n s c的代价是n*s大小单位+ n*c执行单位。
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;
如果你的程序是一个小程序,它会在你使用了你的向量之后退出这个过程,那么我甚至不会费事去释放它们。如果不是,那么就运行for(auto it=v.b ubegin ();it!= v.d ude();+ it)删除*它;