如何判断哪个 class 拥有指针

How to tell which class owns a pointer

我正在观看一个关于智能指针的视频(下面的视频 link),它指出传统 C++ 指针存在以下问题:

你分不清谁拥有指针

Hebert 继续给出以下示例:Class A 有一个指向浮点数的指针,class B 有一个指向同一个浮点数的指针。两者中的哪一个拥有指针?好吧,你看不出来……不清楚……我们不知道删除指针是谁的工作……不好……令人费解……难以调试。

他到底在说什么?我们怎么不知道哪个 class 拥有指针?如果指针是作为 class A 或 B 的实例的一部分创建的,那么它不会简单地分别是 A->myPointer 和 B->myPointer 吗?

谢谢 :^) 基思

https://www.youtube.com/watch?v=Jc9n9BcYSj4
大约在 1:00

编辑

#include <iostream>
class A {
public: float * f_ptr;
};
class B {
public: float * f_ptr;
};
int main() {
    float f=2.71;
    A* a = new(A);
    B* b = new(B);
    a->f_ptr = &f;
    b->f_ptr = &f;
    std::cout << "a->f_ptr: " << *a->f_ptr << std::endl;
    std::cout << "b->f_ptr: " << *b->f_ptr << std::endl;
    delete a;
    delete b;
    std::cout << std::endl;
}

/************
OUTPUT

a->f_ptr: 2.71
b->f_ptr: 2.71

*/

编辑 2

下面post很好的解释了这个现象:
http://ericlavesson.blogspot.com/2013/03/c-ownership-semantics.html

好或坏,但 C 和 C++ 语言没有对指针指向的内存的所有权建立任何规则。这具有非常深远的影响。到今天为止,在这里建立任何规则都为时已晚。大量现有代码将被破坏。

可以在应用程序级别决定谁拥有指针以及谁只使用它。但这是应用程序员的决定,而不是语言的规则。并且应记录此决定(通常使用注释)并传达给将继续使用此代码的人员。

有些人认为显式所有权是一种不好的做法,智能指针才是正确的做法。有些人认为具有明确所有权的模式仍然可以。

指针本身(地址)和指向的内存是有区别的。

每个 class 拥有它的指针,但技术上没有人拥有指向的内存。它 必须以某种方式进行管理(如果未分配,则为段错误;如果已解除分配两次,则为双重释放;如果根本未解除分配,则为内存泄漏)但这完全取决于程序员。可以让 class 负责一些内存(通过让 class 的构造函数和析构函数管理它)但这纯粹是一种约定,而不是语言功能。如果其他 classes 获得了 address/pointer 的副本,他们将不会被拒绝释放或重新分配此内存的权利(尽管这通常是一个非常糟糕的主意)。

当他说一些 class "owns the pointer" 时,这意味着这个 class 负责清理指针造成的混乱。您可以有两个不同的 classes A 和 B,它们使用指向同一对象的指针。除非你是这些 classes 的设计者,否则你无法判断最后应该删除哪个对象并在它之后进行清理,例如解锁一些资源。你无法通过使用一些内置的语言语义来弄清楚或设置它 - 你必须被告知它,例如通过文档。如果设计不好,您可能会遇到两个 class 尝试在同一个对象之后清理两次或者根本不在对象之后清理。

从技术上讲,这是关于谁拥有指针指向的内存,而不是指针本身,但是大多数人在谈论拥有指针时都会参考我上面描述的问题。

智能指针很少能解决上述问题。不过,它们通常是另一个问题的解决方案。

此处概述的问题是共享所有权的问题。当 AB 'own' 资源,谁负责释放它? std::shared_pointer 是一个引用计数指针,一旦它的所有用户都离开,它就会释放资源。但是,应该避免这种情况。在程序中共享指针使得争论资源的生命周期变得极其困难。尽管使用 shared_pointer 的情况很少(通常是多线程队列的情况),但最好尽量避免共享所有权 - 顺便说一下,就像在现实生活中一样:)。相反,让一个 class 成为所有者,另一个成为用户,并以用户永远不会比所有者长寿的方式设计您的界面。它并不像看起来那么难,而且这种设计将使程序维护更容易。

一旦您确定了所有者,std::unique_ptr 是一个不错的选择。它让您无忧无虑地使指针的生命周期等于父对象的生命周期,防止危险的复制分配,并且是异常安全的。