何时将对象值添加到堆上的向量是否安全?

时间:2021-02-19 18:08:50

Let's say I have a structure named vertex with a method that adds two vertices:

假设我有一个名为vertex的结构,其方法是添加两个顶点:

struct vertex {
    float x, y, z;

    // constructs the vertex with initial values
    vertex(float ix, float iy, float iz);

    // returns the value c = this + b
    vertex operator+(vertex b);
};

vertex::vertex(float ix, float iy, float iz){
    this->x = ix; this->y = iy; this->z = iz;
}

vertex vertex::operator+(vertex b){
    vertex c;
    c.x = this->x + b.x;
    c.y = this->y + b.y;
    c.z = this->z + b.z;
    return c;
}

In another calling function I want to add two vertices together and add the result to a vector<vertex*>. When is it safe to use the returned value to add to the given vector? If never, how would I implement it?

在另一个调用函数中,我想在一起添加两个顶点,并将结果添加到向量 。何时使用返回值添加到给定向量是否安全?如果从来没有,我将如何实施它?

For example,

vector<vertex*> v;
vertex a(1, 2, 3);
vertex b(4, 5, 6);
v.push_back(&(a + b));

4 个解决方案

#1


This is not safe, since you are storing a pointer to an automatic or temporary variable, which will be reclaimed when the current function terminates.

这是不安全的,因为您正在存储指向自动或临时变量的指针,当当前函数终止时,该变量将被回收。

Mixing dynamically allocated objects with automatically-allocated ones is a serious risk. Sometimes the best strategy is to completely disallow automatic allocation (e.g., by making the constructor private and using a factory method to create new instance). You would then be responsible for eliminating these at some point.

将动态分配的对象与自动分配的对象混合是一个严重的风险。有时,最好的策略是完全禁止自动分配(例如,通过使构造函数为私有并使用工厂方法来创建新实例)。然后,您将负责在某些时候消除这些。

A second option (not necessarily what you want) is to do everything by value. Have a vector of Vertex rather than Vertex*, and just have the vertices copied when they are stored. The way your class is written, all the fields are primitives, so this might be good enough and you wouldn't run into performance or deep-copy semantic problems.

第二种选择(不一定是你想要的)是按价值做所有事情。有一个Vertex而不是Vertex *的矢量,只是在存储顶点时复制它们。编写类的方式,所有字段都是原语,因此这可能足够好,您不会遇到性能或深层复制的语义问题。

#2


It's never save, since you add a pointer to a temporary object to the vector. That temporary object will be destroyed after the line is executed, leaving the vector with an invalid pointer.

它永远不会保存,因为您向向量添加了一个指向临时对象的指针。在执行该行之后,该临时对象将被销毁,从而使向量具有无效指针。

You have two possibilities. Either you don't store pointers in the vector and use a vector<vertex> instead, or you explicitly allocate a new copy of the temporary object when you add it:

你有两种可能性。您可以不在向量中存储指针,而是使用向量 ,或者在添加临时对象时显式分配临时对象的新副本:

v.push_back(new vertex(a+b));

#3


Another alternative is insert smart-pointer into std container, such as boost:shared_ptr, since the shared pointer will take care of the memory management for you. However, you need return a shared pointer from Shared_Ptr vertex::operator+(vertex b), that means the return value will still be on the heap.

另一种方法是将智能指针插入到std容器中,例如boost:shared_ptr,因为共享指针将为您处理内存管理。但是,您需要从Shared_Ptr vertex :: operator +(顶点b)返回一个共享指针,这意味着返回值仍将在堆上。

If you are not familiar with boost:shared_ptr, then just to do everything by value as suggested by the other posts. This is actually stl standard practice.

如果您不熟悉boost:shared_ptr,那么只需按照其他帖子的建议按值执行所有操作。这实际上是标准做法。

#4


This is not safe, because the vertex values that you are adding to the vector are not on the heap. The returned vertex objects are on the stack, so their memory locations may be overwritten once the current function terminates. If the vector (or a copy of it) persists after the current function ends, there is no guarantee that its pointers will still be referring valid vertex objects.

这不安全,因为要添加到向量的顶点值不在堆上。返回的顶点对象位于堆栈上,因此一旦当前函数终止,它们的内存位置可能会被覆盖。如果在当前函数结束后向量(或其副本)仍然存在,则无法保证其指针仍将引用有效的顶点对象。

The most dangerous part of this situation is that those vertex objects may survive in memory long after the function in which they were created ends. I saw an example of this once, where a student filled a vector with pointers to value objects in a very long constructor. The vector was a member field in the object, so it still existed after the constructor ended. Because the constructor was so long, the value objects that the vector pointed to were not overwritten until halfway through a different function. Watching the vector's contents in a debugger created the perplexing illusion that the objects were spontaneously corrupting in memory.

这种情况中最危险的部分是那些顶点对象可能在它们被创建的函数结束后很长时间内在内存中存活。我曾经看过一个这样的例子,一个学生在一个非常长的构造函数中填充了一个带有指向值对象的向量。向量是对象中的成员字段,因此它在构造函数结束后仍然存在。因为构造函数太长,所以向量指向的值对象直到不同函数的中途才被覆盖。在调试器中观察向量的内容会产生令人困惑的错觉,即对象在内存中会自发地破坏。

Unless you really need to store those vertices as pointers, the safest strategy is to store them as value objects in the vector: vector<vertex> instead of vector<vertex*>. You will still be able to chain the different operators together; in fact, it should be easier to change them together as value objects because you will not constantly need to dereference pointers.

除非您确实需要将这些顶点存储为指针,否则最安全的策略是将它们存储为向量中的值对象:vector 而不是vector 。您仍然可以将不同的运营商联系在一起;实际上,将它们一起更改为值对象应该更容易,因为您不会经常需要取消引用指针。

#1


This is not safe, since you are storing a pointer to an automatic or temporary variable, which will be reclaimed when the current function terminates.

这是不安全的,因为您正在存储指向自动或临时变量的指针,当当前函数终止时,该变量将被回收。

Mixing dynamically allocated objects with automatically-allocated ones is a serious risk. Sometimes the best strategy is to completely disallow automatic allocation (e.g., by making the constructor private and using a factory method to create new instance). You would then be responsible for eliminating these at some point.

将动态分配的对象与自动分配的对象混合是一个严重的风险。有时,最好的策略是完全禁止自动分配(例如,通过使构造函数为私有并使用工厂方法来创建新实例)。然后,您将负责在某些时候消除这些。

A second option (not necessarily what you want) is to do everything by value. Have a vector of Vertex rather than Vertex*, and just have the vertices copied when they are stored. The way your class is written, all the fields are primitives, so this might be good enough and you wouldn't run into performance or deep-copy semantic problems.

第二种选择(不一定是你想要的)是按价值做所有事情。有一个Vertex而不是Vertex *的矢量,只是在存储顶点时复制它们。编写类的方式,所有字段都是原语,因此这可能足够好,您不会遇到性能或深层复制的语义问题。

#2


It's never save, since you add a pointer to a temporary object to the vector. That temporary object will be destroyed after the line is executed, leaving the vector with an invalid pointer.

它永远不会保存,因为您向向量添加了一个指向临时对象的指针。在执行该行之后,该临时对象将被销毁,从而使向量具有无效指针。

You have two possibilities. Either you don't store pointers in the vector and use a vector<vertex> instead, or you explicitly allocate a new copy of the temporary object when you add it:

你有两种可能性。您可以不在向量中存储指针,而是使用向量 ,或者在添加临时对象时显式分配临时对象的新副本:

v.push_back(new vertex(a+b));

#3


Another alternative is insert smart-pointer into std container, such as boost:shared_ptr, since the shared pointer will take care of the memory management for you. However, you need return a shared pointer from Shared_Ptr vertex::operator+(vertex b), that means the return value will still be on the heap.

另一种方法是将智能指针插入到std容器中,例如boost:shared_ptr,因为共享指针将为您处理内存管理。但是,您需要从Shared_Ptr vertex :: operator +(顶点b)返回一个共享指针,这意味着返回值仍将在堆上。

If you are not familiar with boost:shared_ptr, then just to do everything by value as suggested by the other posts. This is actually stl standard practice.

如果您不熟悉boost:shared_ptr,那么只需按照其他帖子的建议按值执行所有操作。这实际上是标准做法。

#4


This is not safe, because the vertex values that you are adding to the vector are not on the heap. The returned vertex objects are on the stack, so their memory locations may be overwritten once the current function terminates. If the vector (or a copy of it) persists after the current function ends, there is no guarantee that its pointers will still be referring valid vertex objects.

这不安全,因为要添加到向量的顶点值不在堆上。返回的顶点对象位于堆栈上,因此一旦当前函数终止,它们的内存位置可能会被覆盖。如果在当前函数结束后向量(或其副本)仍然存在,则无法保证其指针仍将引用有效的顶点对象。

The most dangerous part of this situation is that those vertex objects may survive in memory long after the function in which they were created ends. I saw an example of this once, where a student filled a vector with pointers to value objects in a very long constructor. The vector was a member field in the object, so it still existed after the constructor ended. Because the constructor was so long, the value objects that the vector pointed to were not overwritten until halfway through a different function. Watching the vector's contents in a debugger created the perplexing illusion that the objects were spontaneously corrupting in memory.

这种情况中最危险的部分是那些顶点对象可能在它们被创建的函数结束后很长时间内在内存中存活。我曾经看过一个这样的例子,一个学生在一个非常长的构造函数中填充了一个带有指向值对象的向量。向量是对象中的成员字段,因此它在构造函数结束后仍然存在。因为构造函数太长,所以向量指向的值对象直到不同函数的中途才被覆盖。在调试器中观察向量的内容会产生令人困惑的错觉,即对象在内存中会自发地破坏。

Unless you really need to store those vertices as pointers, the safest strategy is to store them as value objects in the vector: vector<vertex> instead of vector<vertex*>. You will still be able to chain the different operators together; in fact, it should be easier to change them together as value objects because you will not constantly need to dereference pointers.

除非您确实需要将这些顶点存储为指针,否则最安全的策略是将它们存储为向量中的值对象:vector 而不是vector 。您仍然可以将不同的运营商联系在一起;实际上,将它们一起更改为值对象应该更容易,因为您不会经常需要取消引用指针。