通过使用新指针放置此指针导致的C++内存泄漏?
正如我们所知,placement new只构造一个对象,而不分配任何内存。另外,类资源中的所有成员都是对象,而不是指针,尽管std::string内部包含一个动态数组,当std::string对象被销毁时,该数组将被释放。并且*这指向堆栈上分配的内存,这意味着将始终调用析构函数。所以我认为placement new在这里所做的只是覆盖原始对象。下面是一个简单的例子。当我在VS2019上运行这个示例时,内存使用量一直在增加通过使用新指针放置此指针导致的C++内存泄漏?,c++,C++,正如我们所知,placement new只构造一个对象,而不分配任何内存。另外,类资源中的所有成员都是对象,而不是指针,尽管std::string内部包含一个动态数组,当std::string对象被销毁时,该数组将被释放。并且*这指向堆栈上分配的内存,这意味着将始终调用析构函数。所以我认为placement new在这里所做的只是覆盖原始对象。下面是一个简单的例子。当我在VS2019上运行这个示例时,内存使用量一直在增加 class Resource { public: Resource
class Resource
{
public:
Resource() {};
Resource(const std::string& s) : str(s)
{
new(this)Resource();
}
private:
std::string str;
};
int main()
{
while (true)
Resource resource("hello");
}
最新的标准草案说: [基本生活] 程序可以通过重用对象占用的存储来结束任何对象的生命周期。。。如果没有显式调用析构函数,或者如果没有使用删除表达式释放存储,则不会隐式调用析构函数,并且依赖析构函数产生的副作用的任何程序都具有未定义的行为 因此,由于构造函数对动态对象重用*this的存储,而不调用原始对象的析构函数,因此该析构函数永远不会被调用。该析构函数是销毁字符串成员并释放其内存的位置
结论:不要把新的内容放在这上面。最新的标准草案说: [基本生活] 程序可以通过重用对象占用的存储来结束任何对象的生命周期。。。如果没有显式调用析构函数,或者如果没有使用删除表达式释放存储,则不会隐式调用析构函数,并且依赖析构函数产生的副作用的任何程序都具有未定义的行为 因此,由于构造函数对动态对象重用*this的存储,而不调用原始对象的析构函数,因此该析构函数永远不会被调用。该析构函数是销毁字符串成员并释放其内存的位置
结论:不要在*this上放置new。在放置new:this->~Resource;之前调用析构函数;。在这里使用placement new基本上只是在旧字符串上复制memcopies,这意味着旧字符串的内容丢失。因为短字符串优化可能需要比hello更长的字符串才能在某些平台上消除错误。实际上,大多数情况下。如果内存用于实现细节,64位平台在动态分配内存之前可以容纳21个字符加上终止符,而在32位平台上可以容纳9个字符加上终止符。不过,在分配STR后构建此布局时,我有点不以为然……应该没有理由在这上面使用新的布局;您可以简单地使用一个委托构造函数到默认构造函数,这将具有相同的效果,因为您将立即清除给定给它的值str@DanielLangr为一个生命周期尚未开始的对象调用析构函数确实是错误的。我怀疑这种构造的合法性与在构造函数中对此使用placement new是一样的,不过正如公认的答案所解释的那样。在placement new之前调用析构函数:this->~Resource;。在这里使用placement new基本上只是在旧字符串上复制memcopies,这意味着旧字符串的内容丢失。因为短字符串优化可能需要比hello更长的字符串才能在某些平台上消除错误。实际上,大多数情况下。如果内存用于实现细节,64位平台在动态分配内存之前可以容纳21个字符加上终止符,而在32位平台上可以容纳9个字符加上终止符。不过,在分配STR后构建此布局时,我有点不以为然……应该没有理由在这上面使用新的布局;您可以简单地使用一个委托构造函数到默认构造函数,这将具有相同的效果,因为您将立即清除给定给它的值str@DanielLangr为一个生命周期尚未开始的对象调用析构函数确实是错误的。我怀疑这种构造的合法性与在构造器中使用新的布局是一样的,尽管正如公认的答案所解释的那样。