构造函数对象赋值是否泄漏内存

Do constructor object assignments leak memory

本文关键字:泄漏 内存 是否 赋值 对象 构造函数      更新时间:2023-10-16

假设我有一个简单的类,如下所示:


class MyObj
{
char* myPtr;
public: 
MyObj()
{
myPtr = malloc(30);
}
~MyObj()
{
free(myPtr);
}
} 
class TestObject
{
MyObj _myObj;
public:
TestObject(MyObj myObj) 
{
_myObj = myObj;
}
};

这会泄漏内存吗?我的理由是,在构造函数运行时,TestObject 中已经包含一个 MyObj 实例,那么在释放内存之前,这不会吹走 myPtr 吗?分配给本地对象是否会调用被替换对象的析构函数?如果对象实例变量直接在构造函数中赋值,编译器是否会优化对象实例变量的赋值?我来自 C#,其中对象不会仅通过声明引用类型变量来自动初始化,所以这让我有点困惑。

谢谢!

这会

泄漏内存吗?

是的myObj赋值将调用默认的复制赋值运算符,因为您未提供覆盖。因此,将执行逐个成员复制,并用分配源中的myPtr实例覆盖分配目标的myPtr实例。在违反三/五/零规则的一个或多个部分时,经常会遇到两个问题:

  1. 您将丢失作业目标的原始myPtr内容。因此,该指针唯一引用的原始内存被泄漏。
  2. 现在,您可以在两个myPtr成员中共享相同的指针值:赋值操作的源目标。

后者尤其令人不安,因为myObjTestObject构造函数中完成赋值后立即离开范围。这样做,myObj将被摧毁,随之而来的是,它myPtr释放。此外,myObj是通过而不是引用传递给该构造函数的,因此隐式副本很可能已经发生(由于右值移动语义,省略了副本(。因此,三个MyObj对象很可能正在吊起一个myPtr,它们都引用了相同的内存,一旦一个释放它,其余的都在不知不觉中悬挂着悬空的指针。对这些指针的任何取消引用或free-ing 都将调用未定义的行为

分配给本地对象是否会调用被替换对象的析构函数?

析构函数仅被调用以保持其同名。 即,仅在对象被销毁时调用它们(尽管手动调用析构函数以进行放置 - 新语义(。除非引入临时,否则复制赋值不会这样做,而代码中的情况并非如此。

如果对象实例变量

直接在构造函数中赋值,编译器是否会优化对象实例变量的赋值?

否,但成员初始化列表可以在这方面提供帮助。


现代C++编程技术经常使用RAII以多种方式完成您似乎正在尝试的事情,具体取决于您真正想要实现的目标。

每个实例的唯一数据

如果目标是每个实例的唯一动态数据,则可以根据基本需求,使用std::vector<char>或简单地std::string轻松完成此操作。两者都是 RAII 数据类型,通常足以满足动态内存管理需求。

class MyObj
{
std::vector<char> myData;
public: 
MyObj() : myData(30)
{
}
} 
class TestObject
{
MyObj _myObj;
public:
TestObject(MyObj myObj)
: _myObj(std::move(myObj))
{
}
};

这消除了MyObj中析构函数的需要,并在TestObject构造函数中使用了移动语义以及前面提到的成员初始化列表。MyObj的所有实例都将提升一个独特的char向量。MyObjTestObject的所有分配操作都使用默认实现。

作业共享内存

你不太可能想要这个,但它同样可行:

class MyObj
{
std::shared_ptr<char> myPtr;
public: 
MyObj() : myPtr(new char[30])
{
}
};
class TestObject
{
MyObj _myObj;
public:
TestObject(MyObj myObj) 
: _myObj(std::move(myObj))
{
}
};

代码相似,但成员类型不同。现在myPtr是指向char数组的共享指针。对其他myPtr的任何分配都将加入共享列表。简而言之,赋值意味着两个对象引用相同的数据,引用计数确保最后一个人站立扫除混乱。

注意:使用这样的共享指针可能会发生内存泄漏,因为new可能会成功,但共享指针的共享数据块可能会引发异常。这在第 17 C++中得到解决, 其中std::make_shared支持阵列分配


这些只是完成您可能尝试完成的任务的几种方法。我鼓励您在提供的链接和本网站上阅读有关三/五/零规则和 RAII 概念的信息。有很多例子可能会回答您可能遇到的更多问题。