智能指针如何影响 5 的规则?
How do smart pointers affect the rule of 5?
我知道当你在 class 中使用指针时,你应该执行 5 的规则。如果你不使用指针那么你没关系,事实上它更可取,使用默认值。但是,这如何与智能指针一起工作?例如,包含 int*
的 class 可能如下所示:
class A {
private:
int *num_;
public:
explicit A(int* num) : num_(num) {}
~A() {
delete num_;
}
A(const A &other) {
if (this != &other) {
num_ = other.num_;
}
}
A(A &&other) noexcept {
if (this != &other) {
num_ = other.num_;
}
}
A &operator=(A &other) {
if (this == &other) {
this->num_ = other.num_;
}
return *this;
}
A &operator=(A &&other) noexcept {
if (this == &other) {
this->num_ = other.num_;
}
return *this;
};
};
但是如果我们使用智能指针,仅仅这样做就够了吗?
class B {
private:
std::unique_ptr<int> num_;
public:
explicit B(int num) : num_(std::make_unique<int>(num)) {};
};
如果您使用智能指针(或任何 std:: 容器),class 默认析构函数将调用智能指针(和容器)的析构函数。
更多关于此主题的信息:Why doesn't the C++ default destructor destroy my objects?
是的,这就足够了。唯一指针确实管理内存。但是,您的两个 类 的行为会有所不同,因为 std::unique_ptr
无法复制,因此不会有编译器生成的复制构造函数,也不会为 B
.
赋值
另请注意,您实现了 5 规则的所有方法,但未正确实现。如评论中所述,复制 A
将导致两个实例具有相同的指针并在销毁时将其删除。实际上,正确地做到这一点是关于 3/5 规则的全部要点,以及为什么您应该更喜欢 0 规则。
它们有不同的行为。 A
可以复制,B
只能移动。
N.B。您对 A
的实施是不安全的,它可能导致泄漏和未定义的行为。
同类比较要么是delete
A
的复制
class A {
private:
int *num_;
public:
explicit A(int num) : num_(new int(num)) {}
~A() {
delete num_;
}
A(const A &other) = delete;
A(A &&other) noexcept
: num_(std::exchange(other.num, nullptr)) {}
A &operator=(const A &other) =delete;
A &operator=(A &&other) noexcept {
swap(num_, other.num_);
return *this;
};
};
class B {
private:
std::unique_ptr<int> num_;
public:
explicit B(int num) : num_(std::make_unique<int>(num)) {};
};
或定义B
的副本
class A {
private:
int *num_;
public:
explicit A(int num) : num_(new int(num)) {}
~A() {
delete num_;
}
A(const A &other)
: A(other.num) {}
A(A &&other) noexcept
: num_(std::exchange(other.num, nullptr)) {}
A &operator=(const A &other) {
*num_ = *other.num;
return *this;
}
A &operator=(A &&other) noexcept {
swap(num_, other.num_);
return *this;
};
};
class B {
private:
std::unique_ptr<int> num_;
public:
explicit B(int num) : num_(std::make_unique<int>(num)) {};
~B() = default;
B(const B & other) : B(*other.num_) {}
B(B && other) = default;
B& operator=(const B & other) { *num_ = *other.num_ }
B& operator=(B && other) = default;
};
我知道当你在 class 中使用指针时,你应该执行 5 的规则。如果你不使用指针那么你没关系,事实上它更可取,使用默认值。但是,这如何与智能指针一起工作?例如,包含 int*
的 class 可能如下所示:
class A {
private:
int *num_;
public:
explicit A(int* num) : num_(num) {}
~A() {
delete num_;
}
A(const A &other) {
if (this != &other) {
num_ = other.num_;
}
}
A(A &&other) noexcept {
if (this != &other) {
num_ = other.num_;
}
}
A &operator=(A &other) {
if (this == &other) {
this->num_ = other.num_;
}
return *this;
}
A &operator=(A &&other) noexcept {
if (this == &other) {
this->num_ = other.num_;
}
return *this;
};
};
但是如果我们使用智能指针,仅仅这样做就够了吗?
class B {
private:
std::unique_ptr<int> num_;
public:
explicit B(int num) : num_(std::make_unique<int>(num)) {};
};
如果您使用智能指针(或任何 std:: 容器),class 默认析构函数将调用智能指针(和容器)的析构函数。 更多关于此主题的信息:Why doesn't the C++ default destructor destroy my objects?
是的,这就足够了。唯一指针确实管理内存。但是,您的两个 类 的行为会有所不同,因为 std::unique_ptr
无法复制,因此不会有编译器生成的复制构造函数,也不会为 B
.
另请注意,您实现了 5 规则的所有方法,但未正确实现。如评论中所述,复制 A
将导致两个实例具有相同的指针并在销毁时将其删除。实际上,正确地做到这一点是关于 3/5 规则的全部要点,以及为什么您应该更喜欢 0 规则。
它们有不同的行为。 A
可以复制,B
只能移动。
N.B。您对 A
的实施是不安全的,它可能导致泄漏和未定义的行为。
同类比较要么是delete
A
的复制
class A {
private:
int *num_;
public:
explicit A(int num) : num_(new int(num)) {}
~A() {
delete num_;
}
A(const A &other) = delete;
A(A &&other) noexcept
: num_(std::exchange(other.num, nullptr)) {}
A &operator=(const A &other) =delete;
A &operator=(A &&other) noexcept {
swap(num_, other.num_);
return *this;
};
};
class B {
private:
std::unique_ptr<int> num_;
public:
explicit B(int num) : num_(std::make_unique<int>(num)) {};
};
或定义B
的副本
class A {
private:
int *num_;
public:
explicit A(int num) : num_(new int(num)) {}
~A() {
delete num_;
}
A(const A &other)
: A(other.num) {}
A(A &&other) noexcept
: num_(std::exchange(other.num, nullptr)) {}
A &operator=(const A &other) {
*num_ = *other.num;
return *this;
}
A &operator=(A &&other) noexcept {
swap(num_, other.num_);
return *this;
};
};
class B {
private:
std::unique_ptr<int> num_;
public:
explicit B(int num) : num_(std::make_unique<int>(num)) {};
~B() = default;
B(const B & other) : B(*other.num_) {}
B(B && other) = default;
B& operator=(const B & other) { *num_ = *other.num_ }
B& operator=(B && other) = default;
};