为什么需要复制构造函数,它们在什么情况下非常有用?
why are copy constructors needed and what are the cases where they are very helpful?
为什么我们需要复制构造函数?
我正在学习 C++,但我无法理解复制构造函数的必要性,因为在不使用复制构造函数的情况下,我也得到了正确的输出。
我经历了几个例子,但在我看来,拥有复制构造函数只是一种很好的做法,比如初始化变量。有人可以帮助我理解复制构造函数的概念。
非常感谢任何帮助。
谢谢。
如果您通过复制传递将对象传递给方法,C++ 必须使用复制构造函数为方法上下文生成 class 的实例。例如,如果您将实例存储在向量中,当您推回一个对象时,它会间接调用复制构造函数。顺便说一下,对于 classes,如果没有显式实现的复制构造函数,c++ 通常会创建一个默认的复制构造函数,这种情况有时会产生不需要的效果(浅复制)。
让我们看下一个例子
#include <iostream>
struct A {
explicit A(int value) : data_(new int[1]) { data_[0] = value; }
~A() { delete [] data_; }
int getValue() const { return data_[0]; }
private:
int *data_ = nullptr;
};
int main() {
A a1(1);
A a2(2);
a2 = a1;
std::cout << a2.getValue() << std::endl;
}
如果你执行它,程序会崩溃。
这里发生的是您将 int *data_
字段从 a1
复制到 a2
,然后由 a2
分配的内存被泄漏。
现在 a1
和 a2
有相同的指针。他们都将调用析构函数来释放内存。内存会被释放两次,导致崩溃。
提供正确的复制构造函数将解决此问题。
三的法则(也称为三巨头法则或三巨头)是 C++(C++11 之前)中的一条经验法则,声称如果 class 定义以下任何一项,那么它可能应该明确定义所有三个:析构函数。复制构造函数。复制赋值运算符。
要点:当您在对象构造函数中进行动态内存分配(堆)时,复制构造函数是必需的,您还需要将分配的内存复制到新分配的对象。这样你就可以
(Obj1 = Obj2 / Obj1(Obj2) ) 并保证动态内存也将被复制。
because without using a copy constructor also, we can get the desired
output
事实并非如此。您没有编写复制构造函数,但您通过编译器为您编写的复制构造函数获得了所需的输出:
If no user-defined copy constructors are provided for a class type
(struct, class, or union), the compiler will always declare a copy
constructor as a non-explicit inline public member of its class
有关隐式声明的复制构造函数的更多详细信息,请参见https://en.cppreference.com/w/cpp/language/copy_constructor。
简而言之,复制构造函数是在复制 class 实例时调用的函数。编译器为您编写它,但如果您希望它做一些重要的事情,您可以自己编写它(例如不是复制指针而是复制它指向的对象)
为什么我们需要复制构造函数?
我正在学习 C++,但我无法理解复制构造函数的必要性,因为在不使用复制构造函数的情况下,我也得到了正确的输出。 我经历了几个例子,但在我看来,拥有复制构造函数只是一种很好的做法,比如初始化变量。有人可以帮助我理解复制构造函数的概念。 非常感谢任何帮助。 谢谢。
如果您通过复制传递将对象传递给方法,C++ 必须使用复制构造函数为方法上下文生成 class 的实例。例如,如果您将实例存储在向量中,当您推回一个对象时,它会间接调用复制构造函数。顺便说一下,对于 classes,如果没有显式实现的复制构造函数,c++ 通常会创建一个默认的复制构造函数,这种情况有时会产生不需要的效果(浅复制)。
让我们看下一个例子
#include <iostream>
struct A {
explicit A(int value) : data_(new int[1]) { data_[0] = value; }
~A() { delete [] data_; }
int getValue() const { return data_[0]; }
private:
int *data_ = nullptr;
};
int main() {
A a1(1);
A a2(2);
a2 = a1;
std::cout << a2.getValue() << std::endl;
}
如果你执行它,程序会崩溃。
这里发生的是您将 int *data_
字段从 a1
复制到 a2
,然后由 a2
分配的内存被泄漏。
现在 a1
和 a2
有相同的指针。他们都将调用析构函数来释放内存。内存会被释放两次,导致崩溃。
提供正确的复制构造函数将解决此问题。
三的法则(也称为三巨头法则或三巨头)是 C++(C++11 之前)中的一条经验法则,声称如果 class 定义以下任何一项,那么它可能应该明确定义所有三个:析构函数。复制构造函数。复制赋值运算符。
要点:当您在对象构造函数中进行动态内存分配(堆)时,复制构造函数是必需的,您还需要将分配的内存复制到新分配的对象。这样你就可以 (Obj1 = Obj2 / Obj1(Obj2) ) 并保证动态内存也将被复制。
because without using a copy constructor also, we can get the desired output
事实并非如此。您没有编写复制构造函数,但您通过编译器为您编写的复制构造函数获得了所需的输出:
If no user-defined copy constructors are provided for a class type (struct, class, or union), the compiler will always declare a copy constructor as a non-explicit inline public member of its class
有关隐式声明的复制构造函数的更多详细信息,请参见https://en.cppreference.com/w/cpp/language/copy_constructor。
简而言之,复制构造函数是在复制 class 实例时调用的函数。编译器为您编写它,但如果您希望它做一些重要的事情,您可以自己编写它(例如不是复制指针而是复制它指向的对象)