是的,重点std::observer_ptr
主要是“自我记录”,这本身就是一个有效的目的。但应该指出的是,可以说它在这方面做得并不好,因为“观察者”指针到底是什么并不明显。首先,正如 Galik 指出的那样,对于某些人来说,这个名字似乎暗示着不修改目标的承诺,这不是本意,所以像这样的名字access_ptr
会更好。其次,如果没有任何限定词,该名称将暗示对其“非功能性”行为的认可。例如,人们可能认为 anstd::weak_ptr
是一种“观察者”指针。但是std::weak_ptr
通过提供一种允许尝试访问(解除分配的)对象安全失败的机制来适应指针比目标对象寿命更长的情况。std::observer_ptr
的实现不适应这种情况。所以也许raw_access_ptr
是一个更好的名字,因为它可以更好地表明它的功能缺陷。
那么,正如您有理由问的那样,这个功能受到挑战的“非拥有”指针有什么意义?主要原因可能是性能。许多 C++ 程序员认为 a 的开销std::share_ptr
太高,因此在他们需要“观察者”指针时只会使用原始指针。所提议的std::observer_ptr
尝试以可接受的性能成本提供代码清晰度的小幅改进。具体来说,零性能成本。
不幸的是,对于使用原始指针作为“观察者”指针的安全性,似乎存在一种普遍但在我看来是不切实际的乐观主义。特别是,虽然很容易声明目标对象必须比std::observer_ptr
. 考虑这个例子:
struct employee_t {
employee_t(const std::string& first_name, const std::string& last_name) : m_first_name(first_name), m_last_name(last_name) {}
std::string m_first_name;
std::string m_last_name;
};
void replace_last_employee_with(const std::observer_ptr<employee_t> p_new_employee, std::list<employee_t>& employee_list) {
if (1 <= employee_list.size()) {
employee_list.pop_back();
}
employee_list.push_back(*p_new_employee);
}
void main(int argc, char* argv[]) {
std::list<employee_t> current_employee_list;
current_employee_list.push_back(employee_t("Julie", "Jones"));
current_employee_list.push_back(employee_t("John", "Smith"));
std::observer_ptr<employee_t> p_person_who_convinces_boss_to_rehire_him(&(current_employee_list.back()));
replace_last_employee_with(p_person_who_convinces_boss_to_rehire_him, current_employee_list);
}
函数的作者可能从未想过,replace_last_employee_with()
对新员工的引用也可能是对要替换的现有员工的引用,在这种情况下,函数可能会无意中导致其std::observer_ptr<employee_t>
参数的目标在完成之前被释放使用它。
这是一个人为的例子,但这种事情很容易在更复杂的情况下发生。当然,在绝大多数情况下使用原始指针是完全安全的。问题是在少数情况下很容易假设它是安全的,而实际上它并不安全。
如果用or替换std::observer_ptr<employee_t>
参数由于某种原因是不可接受的,那么现在有另一个安全选项 - 这是答案的无耻插入部分 - “注册指针”。“注册指针”是智能指针,其行为类似于原始指针,除了它们(自动)设置为目标对象被销毁时,默认情况下,如果您尝试访问已被删除的对象,则会引发异常. 它们通常更快std::shared_ptr
std::weak_ptr
null_ptr
比 std::shared_ptrs,但如果您的性能要求非常严格,注册指针可以通过编译时指令“禁用”(自动替换为对应的原始指针),从而允许在调试中使用(并产生开销)仅限 /test/beta 模式。
因此,如果将有一个基于原始指针的“观察者”指针,那么可以说应该有一个基于注册指针的指针,也许正如 OP 所建议的那样,一个基于 std::shared_ptr 的指针。