C++类中成员有指针时的注意事项

关于类中有new初始化的指针成员.可能出现的问题

分享的内容

  1. 默认拷贝(复制)构造函数、赋值运算符,以及显式拷贝构造函数、赋值运算符
  2. int* p = new int[0]
  3. algrithm库中的sort函数


拷贝(复制)构造函数、赋值运算符

类对象的成员经常需要动态分配内存。例如int* path.用于保存遍历的节点,申请不同的字节长度满足规模大小不同的需求。

如同默认构造函数,当没有定义拷贝(复制)构造函数、赋值运算符时,系统提供默认的拷贝(复制)构造函数、赋值运算符,但是只是简单地将一个对象的数据成员给另一个对象的数据成员进行初始化/赋值(浅拷贝)。当成员有指针时,指针的值(指向的内存块地址)也会一致,两个指针就指向同一内存块。需要显式定义,在函数中重新申请内存(深拷贝),让指针指向申请的内存块,再赋值。

错误的程序例子:

#include <iostream>
#include <string>

using namespace std;

class Test
{
public:
	Test();
	Test(int n);
	~Test();
	void show();

private:
	int length;
	int* path;
};

Test::Test():
	length(0)
{
	cout << "Copy_String::Default Constrution Called." << endl;
	path = NULL;
}
Test::Test(int n)
{
	cout << "Copy_String::Constrution Called." << endl;
	length = n;
	path = NULL;//看上去可能多此一举,但是如果new数据内存分配失败,还可以在其他地方先行判断if(path==NULL)
	path = new int[n];
	if (path != NULL)
	{
		int i;
		for (i = 0; i < length; i++)
		{
			path[i] = i;
		}
	}
	else {
		cout << "path[] alloc failed.\n";
	}
}
Test::~Test()
{
	cout << "Copy_String::Destruction Called." << endl;
	cout << endl;
	if (path != NULL)
	{
		delete[] path;
		path = NULL;
	}
}
void Test::show()
{
	cout << "length:" << length << endl;
	cout << "path:";
	int i;
	for (i = 0; i < length; i++)
	{
		cout << path[i] << " ";
	}
	cout << endl;
	cout << "path.address = " << path << endl;
}

int main()
{
	cout << "无参构造函数.构造对象a" << endl;
	Test a;
	a.show();
	cout << endl;

	{
		cout << "默认赋值运算符.带参对象c给对象a赋值.对象c在函数体内\n";
		Test c(5);
		a = c;
		cout << "c.show()\n";
		c.show();
		cout << "a.show()\n";
		a.show();
		cout << endl;
	}
	cout << "对象c生命周期结束...";
	cout << "a.show()\n";
	a.show();


	cin.get();
	return 0;
}

程序输出:

对象c和

  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在C++编程,有一些实用的注意事项可以帮助你编写更高效、可维护和安全的代码。以下是几个关键点: 1. **类型转换**:使用`static_cast`, `dynamic_cast`, `const_cast`, 和 `reinterpret_cast`要小心,确保类型转换的正确性和意图。滥用类型转换可能导致运行错误或性能损失。 2. **内存管理**:手动管理内存(使用new, delete,指针等)要避免内存泄漏和悬挂指针。使用智能指针(如`shared_ptr`, `unique_ptr`, 或`std::optional`)可以简化内存处理。 3. **异常处理**:尽量遵循"异常不应被忽视"的原则,用`try-catch`块捕获并处理可能的异常。同,避免在finally块释放资源,因为这可能导致资源在异常发生后未得到正确的清理。 4. **命名规范**:遵循一致的命名约定,比如成员变量使用小驼峰式(`camelCase`),函数和类使用大驼峰式(`PascalCase`)。 5. **模板编程**:C++模板可以生成灵活的代码,但过度使用可能导致代码复杂度增加。确保模板参数的数量适,并为模板提供明确的文档。 6. **RAII(Resource Acquisition Is Initialization)**:利用RAII原则,确保在对象生命周期结束自动释放资源,例如文件、锁或动态分配的内存。 7. **范围-based for循环**:对于迭代容器,使用范围-based for循环比传统的迭代器更简洁易读。 8. **STL**:充分利用标准模板库(STL),它提供了高效的数据结构和算法,可以提高代码质量。 9. **避免全局变量**:尽可能减少全局变量,它们增加了耦合度和测试的复杂性。 10. **代码复用**:合理地设计类和模块,以促进代码的复用和模块化。 相关问题: 1. 何为RAII原则? 2. 使用范围-based for循环有何优点? 3. C++为什么要避免全局变量?
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值