std::unique_ptr 及其对 STL 容器中匹配指针的影响
std::unique_ptr and its effect on matching pointers in STL containers
我在我的游戏中为灯光创建了一个工厂 class,其中函数 "create" 创建了一个 unique_ptr 并将其存储在 STL 向量中,因此我可以收集灯光数据并将它发送到着色器,然后它 returns 对向量中 unique_ptr 的引用,如下所示:
std::unique_ptr<Light>& create() {
myVector.push_back(std::unique_ptr<Light>(new Light));
return &myVector.back();
}
但是,当我添加更多灯光时,unique_ptr 引用(不是原始指针)变得无效,因为它引用了向量中的 unique_ptr 对象。因此,在创建后传递 unique_ptr 引用会导致错误。所以,我想出了这个解决方案:
std::unique_ptr<Light> create() {
Light* light = new Light();
myVector.push_back(light);
return std::unique_ptr<Light>(light);
}
这解决了无效问题,但是现在,当 unique_ptr 超出范围时,它将 myVector 中的原始指针替换为向量中的下一个指针。因此,如果我有一个指针向量:[1, 2, 3],那么在 unique_ptr 超出范围后,向量变为 [2, 2, 3]。当然,我不想要冗余数据,所以我用 STL 集替换了矢量。现在,当 unique_ptr 超出范围时,集合会找到冗余数据并删除一个副本,因此集合正确包含指针:[2, 3]。这有效,我没有收到任何错误,但我不明白 unique_ptr 为什么或如何更改 STL 容器中的匹配指针值。这是预期的行为吗?如果是这样,why/how 有效吗?
PS:我理解 unique_ptr 的目的是使指针由一个对象拥有。因此,我更喜欢将唯一所有权保留在调用 create() 函数的对象中。因此,工厂只是简单地创建灯光并存储对它创建的灯光的引用以便于收集,尽管工厂自己完成的存储只是一种临时措施。但是,我喜欢当 unique_ptr 超出范围时自动释放自身时自动维护 STL 集的性质。所以,我想保留这种通用设计,前提是它不是 unique_ptr.
的侥幸。
因为 std::vector<std::unique_ptr<Light>>
是 Light
的所有者,return 引用这些而不是指向 Light
的指针几乎没有用处。这些引用仅在您需要替换值时才有用。我只是根据使用对象而不是拥有对象的 Light*
或 Light const*
来旅行。您可以使用 get()
方法获取 std::unique_ptr<T>
持有的指针。
您 可以 return 一个 simple_ptr<Light>
而不是 return 一个 Light*
,其中 simple_ptr<T>
本质上只是有一个构造函数采用 T*
和运算符 operator->()
其中 return 是 T*
和 operator*()
其中 return 是 T&
:
template <typename T>
class simple_ptr {
T* ptr;
public:
explicit simple_ptr(T* ptr): ptr(ptr) {}
T* operator->() const { return this->ptr; }
T& operator*() const { return *this->ptr; }
};
生成的函数只做正确的事情(即根据需要复制指针)。不跳过篮球就不可能 delete
这个指针。如果你给你的 Light
类型一个自定义的一元 operator&()
你可能会更难明确地找到指针。不过,Tt 并非不可能,因为您总是可以调用 ptr.operator->()
来获取它。但是,只防墨菲,不防马基雅维利
既然您不想在工厂函数的调用者 或 向量有指向它的指针时删除该对象,为什么不使用 std::shared_ptr
?
您试图拥有多个副本,这与 std::unique_ptr
的设计相矛盾。
这可以通过使用 std::shared_ptr
来解决。
std::shared_ptr<Light> create() {
myVector.push_back(std::make_shared<Light>());
return myVector.back();
}
或者,如果您希望矢量主要负责这些灯的生命周期,return 一个 std::weak_ptr
,它知道什么时候悬空。
std::weak_ptr<Light> create() {
myVector.push_back(std::make_shared<Light>());
return myVector.back();
}
智能指针是解决资源所有权的问题。这并不意味着您总是使用 shared_ptr 而从不使用 "raw" 指针。
您似乎想要一个灯光矢量,该矢量负责资源。为此,您甚至不需要指针,因为向量在内部处理指针。
vector<Light> myVector;
您可以从矢量或此创建函数的 return 中获取此资源的句柄。
const Light& create() {
Light light;
myVector.push_back(light);
return myVector.back();
}
此资源的使用者可以做什么?能消光吗?
而vector又能给消费者带来什么保障呢?这些指针是否会在列表的生命周期内被使用。
- 传递 unique_ptr 意味着传递所有权。
- Creating shared_ptr的意思是当最后一个引用被删除时,资源被清理。
- weak_ptr 可用于不关心资源是否被清理的观察者。
- 原始指针和引用不关心任何事情。但是,如果您只是获取一个适当的句柄并读写该实例,则无需处理 share_ptr.
的开销
我在我的游戏中为灯光创建了一个工厂 class,其中函数 "create" 创建了一个 unique_ptr 并将其存储在 STL 向量中,因此我可以收集灯光数据并将它发送到着色器,然后它 returns 对向量中 unique_ptr 的引用,如下所示:
std::unique_ptr<Light>& create() {
myVector.push_back(std::unique_ptr<Light>(new Light));
return &myVector.back();
}
但是,当我添加更多灯光时,unique_ptr 引用(不是原始指针)变得无效,因为它引用了向量中的 unique_ptr 对象。因此,在创建后传递 unique_ptr 引用会导致错误。所以,我想出了这个解决方案:
std::unique_ptr<Light> create() {
Light* light = new Light();
myVector.push_back(light);
return std::unique_ptr<Light>(light);
}
这解决了无效问题,但是现在,当 unique_ptr 超出范围时,它将 myVector 中的原始指针替换为向量中的下一个指针。因此,如果我有一个指针向量:[1, 2, 3],那么在 unique_ptr 超出范围后,向量变为 [2, 2, 3]。当然,我不想要冗余数据,所以我用 STL 集替换了矢量。现在,当 unique_ptr 超出范围时,集合会找到冗余数据并删除一个副本,因此集合正确包含指针:[2, 3]。这有效,我没有收到任何错误,但我不明白 unique_ptr 为什么或如何更改 STL 容器中的匹配指针值。这是预期的行为吗?如果是这样,why/how 有效吗?
PS:我理解 unique_ptr 的目的是使指针由一个对象拥有。因此,我更喜欢将唯一所有权保留在调用 create() 函数的对象中。因此,工厂只是简单地创建灯光并存储对它创建的灯光的引用以便于收集,尽管工厂自己完成的存储只是一种临时措施。但是,我喜欢当 unique_ptr 超出范围时自动释放自身时自动维护 STL 集的性质。所以,我想保留这种通用设计,前提是它不是 unique_ptr.
的侥幸。因为 std::vector<std::unique_ptr<Light>>
是 Light
的所有者,return 引用这些而不是指向 Light
的指针几乎没有用处。这些引用仅在您需要替换值时才有用。我只是根据使用对象而不是拥有对象的 Light*
或 Light const*
来旅行。您可以使用 get()
方法获取 std::unique_ptr<T>
持有的指针。
您 可以 return 一个 simple_ptr<Light>
而不是 return 一个 Light*
,其中 simple_ptr<T>
本质上只是有一个构造函数采用 T*
和运算符 operator->()
其中 return 是 T*
和 operator*()
其中 return 是 T&
:
template <typename T>
class simple_ptr {
T* ptr;
public:
explicit simple_ptr(T* ptr): ptr(ptr) {}
T* operator->() const { return this->ptr; }
T& operator*() const { return *this->ptr; }
};
生成的函数只做正确的事情(即根据需要复制指针)。不跳过篮球就不可能 delete
这个指针。如果你给你的 Light
类型一个自定义的一元 operator&()
你可能会更难明确地找到指针。不过,Tt 并非不可能,因为您总是可以调用 ptr.operator->()
来获取它。但是,只防墨菲,不防马基雅维利
既然您不想在工厂函数的调用者 或 向量有指向它的指针时删除该对象,为什么不使用 std::shared_ptr
?
您试图拥有多个副本,这与 std::unique_ptr
的设计相矛盾。
这可以通过使用 std::shared_ptr
来解决。
std::shared_ptr<Light> create() {
myVector.push_back(std::make_shared<Light>());
return myVector.back();
}
或者,如果您希望矢量主要负责这些灯的生命周期,return 一个 std::weak_ptr
,它知道什么时候悬空。
std::weak_ptr<Light> create() {
myVector.push_back(std::make_shared<Light>());
return myVector.back();
}
智能指针是解决资源所有权的问题。这并不意味着您总是使用 shared_ptr 而从不使用 "raw" 指针。
您似乎想要一个灯光矢量,该矢量负责资源。为此,您甚至不需要指针,因为向量在内部处理指针。
vector<Light> myVector;
您可以从矢量或此创建函数的 return 中获取此资源的句柄。
const Light& create() {
Light light;
myVector.push_back(light);
return myVector.back();
}
此资源的使用者可以做什么?能消光吗?
而vector又能给消费者带来什么保障呢?这些指针是否会在列表的生命周期内被使用。
- 传递 unique_ptr 意味着传递所有权。
- Creating shared_ptr的意思是当最后一个引用被删除时,资源被清理。
- weak_ptr 可用于不关心资源是否被清理的观察者。
- 原始指针和引用不关心任何事情。但是,如果您只是获取一个适当的句柄并读写该实例,则无需处理 share_ptr. 的开销