C++在构造函数中使用new时的注意事项

一、具体注意事项

(1)如果在构造函数中使用new来初始化指针成员,则应在析构函数中使用delete。

(2)new和delete必须相互兼容。new对应于delete,new[]对应于delete[]。

(3)如果有多个构造函数,则必须以相同的方式使用new,要么都带中括号,要么都不带。因为只有一个析构函数,所有的构造函数都必须与它兼容。然而,可以在一个析构函数中使用new初始化指针,而在另一个构造函数中将指针初始化为空(0或C++11中的nullptr),这是因为delete可以用于空指针(无论是带中括号还是不带中括号的new)。

注: NULL、0、nullptr,原先,空指针可以使用0或NULL来表示(在很多头文件中,NULL是一个被定义为0的符号常量)。C程序员通常使用NULL而不是0,以指出这是个指针,就像使用’\0’而不是0来表示空字符,以指出这是一个字符一样。然而C++传统上更喜欢使用0,而不是等价的NULL。但C++11提供了关键字nullptr,这是个更好的选择。

(4)应定义一个复制构造函数,通过深度复制将一个对象初始化为另一个对象。

(5)应当定义一个赋值运算符,通过深度复制将一个对象复制给另一个对象。

二、应该如何做与不应该如何做

2.1 定义的析构函数

// 析构函数释放char* str
String::~String()
{
    delete[] str;
}

2.2 定义如下几种构造函数

// 第一种
String::String()
{
    str = "default string";
    len = std::strlen(str);
}

// 第二种
Str
C++中,拷贝构造函数(Copy Constructor)是用于通过一个已存在的对象初始化新对象的特殊构造函数。其典型形式为 `ClassName(const ClassName& other)`。编译器会自动生成一个默认的拷贝构造函数,但如果需要自定义行为,则必须遵循“五法则”,即同处理其他特殊成员函数(移动构造、拷贝赋值、移动赋值以及析构函数)[^1]。 ### 拷贝构造函数使用场景 1. **显式初始化**:当使用一个已有对象创建新对象,例如: ```cpp MyClass obj1; MyClass obj2 = obj1; // 调用拷贝构造函数 ``` 2. **函数参数传递**:当对象以值的方式传入函数,会调用拷贝构造函数来创建函数内的副本。 ```cpp void func(MyClass obj); MyClass obj; func(obj); // obj 被拷贝进函数内部 ``` 3. **函数返回值**:当函数返回一个对象而非引用或指针,通常也会触发拷贝构造函数(虽然现代编译器可能进行返回值优化 RVO 来避免实际拷贝)。 ```cpp MyClass createObj() { MyClass obj; return obj; // 可能调用拷贝构造函数 } ``` ### 实现拷贝构造函数的最佳实践 1. **深拷贝与浅拷贝**:如果类中包含指针或资源句柄,应实现深拷贝逻辑以避免多个对象共享同一资源导致的问题(如重复释放内存)。 ```cpp class MyClass { public: int* data; MyClass(int value) { data = new int(value); } // 拷贝构造函数 - 深拷贝 MyClass(const MyClass& other) { data = new int(*other.data); // 分配新的内存并复制内容 } ~MyClass() { delete data; } }; ``` 2. **禁止拷贝操作**:如果类的设计不允许拷贝(如管理唯一资源),则应将拷贝构造函数和拷贝赋值运算符设为 `=delete`。 ```cpp class NonCopyable { public: NonCopyable() = default; // 禁止拷贝构造 NonCopyable(const NonCopyable&) = delete; // 禁止拷贝赋值 NonCopyable& operator=(const NonCopyable&) = delete; }; ``` 3. **继承中的拷贝构造函数**:派生类的拷贝构造函数应显式调用基类的拷贝构造函数以确保完整复制。 ```cpp class Base { public: Base() = default; Base(const Base&) { /* 基类拷贝逻辑 */ } }; class Derived : public Base { public: Derived(const Derived& other) : Base(other) { /* 派生类拷贝逻辑 */ } }; ``` 4. **虚析构函数与多态类型**:对于支持多态的类,应提供虚析构函数,并考虑是否删除拷贝操作以防止不安全的拷贝行为。 ```cpp class Base { public: virtual void do_stuff() {} virtual ~Base() = default; // 删除拷贝相关操作 Base(const Base&) = delete; Base& operator=(const Base&) = delete; }; ``` 5. **一致性与异常安全**:拷贝构造函数应保证强异常安全,即在抛出异常不会造成资源泄漏或状态不一致。 ### 注意事项 - 如果未手动定义拷贝构造函数,编译器将生成一个按成员逐个拷贝的版本。此默认行为适用于简单聚合类型,但对涉及动态资源管理的类可能不适用。 - 若类中存在不可拷贝的成员(如 `std::unique_ptr`),则拷贝构造函数会被隐式删除,除非显式定义。 - 使用 `=default` 可以要求编译器生成默认的拷贝构造函数,而 `=delete` 则可用于明确禁止拷贝行为。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值