这是否泄漏记忆?
是。 myObj
的分配将调用默认的复制分配操作符,因为您没有提供覆盖。因此,会执行逐个成员的副本,并且分配目标的myPtr
实例将被来自分配源的myPtr
实例覆盖。这里介绍两个问题,违反了Rule of Three/Five/Zero的一个或多个部件时,经常遇到:
- 您失去从分配的目标原来
myPtr
内容。因此,该指针唯一引用的原始内存被泄漏。
- 您现在的分享相同的指针值在两个
myPtr
成员:来源和分配操作的目标。
后者特别令人不安,因为myObj
在TestObject
构造函数中完成赋值后立即离开范围。在这样做的时候,myObj
将被销毁,并且与此同时,它被释放了myPtr
。此外,myObj
通过在到该构造函数值,而不是引用,所以隐式副本已经可能发生(由于右值移动语义,缺乏副本)。因此, MyObj
对象很可能被吊装myPtr
所有引用相同的内存,并尽快发布一个它,其余的都在不知不觉中提升晃来晃去指针。任何解引用或这些指针的调用将调用未定义的行为。
给本地对象调用分配对象的析构函数吗?
只有调用了析构函数才能与它们同名。也就是说,只有当一个对象被破坏被破坏时(手动调用析构函数进行放置 - 新的语义)时才会调用它们。除非引入临时对象,否则复制分配不会执行该操作,而代码中则不是这种情况。
如果编译器直接在构造函数中赋值,编译器是否会优化对象实例变量的赋值?
不,但member initialization list可以在这方面提供帮助。
现代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
。 MyObj
和TestObject
的所有分配操作都使用默认实现。
分配共享内存
不太可能你想要这个,但它是没有最不具有可行性:
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
是shared pointer到char
的数组。任何分配给不同的myPtr
都将加入共享列表。简而言之,分配意味着两个对象都参考相同的数据,并且引用计数可以确保最后一个人能够清除混乱。
注意:使用像这样的共享指针可能导致内存泄漏,因为new
可能会成功,但共享指针的共享数据块可能会引发异常。这是在C++ 17, 其中std::make_shared
支持数组分配
这些做什么,你可能会尝试完成的只是一些方法解决。我鼓励您在所提供的链接和本网站上阅读关于Rule of Three/Five/Zero和约RAII的概念。有很多例子可能会回答您可能遇到的更多问题。
“这是否泄漏记忆?”你的C++教科书对此有何评论? –
这两个泄漏内存*和*最终双释放内存。总之,你会被迫使这个*更多*错误比现在。 – WhozCraig
为了不存在泄漏问题或双重问题,您需要遵循[rule-of-5](http://en.cppreference.com/w/cpp/language/rule_of_three)。或者走最佳路线并使用'std :: unique_ptr' – Justin