独特的指针和 3 法则
Unique Pointers and The Rule of 3
当我想要多态行为时,我经常发现自己在C++中使用独特的指针。我通常实现如下所示的纯抽象类:
class A {
public:
virtual A* clone() const = 0; // returns a pointer to a deep copy of A
// other methods go here
};
当我想用自己的 A 实例修饰另一个类时,克隆方法会派上用场,例如:
#include <memory>
class B {
private:
std::unique_ptr<A> a_ptr;
public:
// ctor
B(const A& a) {
a_ptr = std::unique_ptr<A>(a.clone());
//...
}
// copy ctor
B(const B& other) : B(*other.a_ptr) {}
};
我总是最终在 B 中实现复制构造函数以避免编译器错误(MSVC 给出一条关于尝试引用已删除函数的模糊消息),由于唯一的指针,这完全有意义。我的问题可以总结如下:
我真的需要 B 中的复制构造函数吗?也许有一个更好的模式可以让我完全避免它。
如果是 1,我可以就此打住吗?我是否需要实现其他默认函数?即是否有任何情况我还需要默认构造函数和析构函数?
在实践中,每当我觉得我需要实现默认函数时,我通常会与其他三个函数一起实现一个 move-constructor;我通常使用复制和交换成语(根据 GManNickG 在此线程中的答案)。我认为这不会改变任何事情,但也许我错了!
多谢!
首先,我认为您的克隆函数的签名可能是
virtual std::unique_ptr<A> clone() = 0;
因为您希望A
实例的深层副本和B
中的独占所有权。其次,当您希望类可复制时,确实必须为类定义一个复制构造函数。赋值运算符也是如此。这是因为std::unique_ptr
是仅移动类型,这会阻碍编译器生成默认实现。
不需要其他特殊成员函数,尽管它们可能有意义。编译器不会为您生成移动构造函数和移动赋值运算符(当您发布自己的复制/赋值函数时),尽管在您的情况下,您可以轻松= default;
它们。析构函数同样可以用= default;
来定义,这将符合核心准则。
请注意,通过= default
定义析构函数应在翻译单元中完成,因为std::unique_ptr
要求在释放其资源时知道完整类型。
是否需要默认构造函数完全取决于你希望如何使用类B
。
正如@lubgr在他的回答中提到的,你应该从clone
函数中返回unique_ptr
而不是原始的。无论如何,转到您的问题:
-
在 B 中需要复制构造函数吗?这取决于您的用例,但是如果您复制类
B
的对象,您可能需要一个。但正如你所说,你经常这样做,所以考虑更通用的方法是明智的。其中之一是为unique_ptr
创建一个包装器,该包装器将具有复制构造函数,并将在此复制构造函数中对此指针进行深层复制。 请考虑以下示例:template<class T> class unique_ptr_wrap { public: unique_ptr_wrap(std::unique_ptr< T > _ptr) : m_ptr(std::move(_ptr)){} unique_ptr_wrap(const unique_ptr_wrap &_wrap){ m_ptr = _wrap->clone(); } unique_ptr_wrap(unique_ptr_wrap &&_wrap){ m_ptr = std::move(_wrap.m_ptr); } T *operator->() const { return m_ptr.get(); } T &operator*() const { return *m_ptr; } private: std::unique_ptr< T > m_ptr; };
- 这再次取决于您的需求。我个人也建议重载移动构造函数,以使其使用更少的动态分配(但这可能是万恶之源的预制优化)。
- 1d 智能指针不适用于语法 (*)++
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 为什么使用 "this" 指针调用派生成员函数?
- 函数向量_指针有不同的原型,我可以构建一个吗
- 使用指针从C++中的数组中获取最大值
- 助记符和指向成员语法的指针
- 嵌入方指针压缩已禁用
- 数组的指针从不分段故障
- C++ 指针的内存地址和指向数组的内存地址如何相同?
- 何时在引用或唯一指针上使用移动语义
- QMetaObject invokeMethod的基于函数指针的语法
- 如何从 std::atomic 中提取指针 T<T>?
- 如何在 C# 中映射双 C 结构指针?
- C++将浮点指针值舍入为小数位数
- 为什么++(*p)更改指针值
- 调整大小后指向元素值的指针unordered_map有效?
- 何时返回指针与返回对象的一般经验法则?
- 独特的指针和 3 法则
- 在C++中使用指针或引用作为函数的返回类型是否有经验法则
- 三法则与智能指针