c++ - 带有标记调度的 const 成员构造函数中的内存泄漏
问题描述
我有一个类Bar
,它有一个类型的成员Foo
。类Foo
应该只在某些固定和恒定的状态下构造,这些状态是基于 a 来区分的Tag
。由于我不想Foo
在任何其他状态下构造,我将其构造函数设为私有并实现了 factory FooFactory
。
在 的Bar
构造函数的初始化列表中,我调用函数,它返回基于make_Foo
的正确实例。Foo
Tag
#include <stdexcept>
#include <string>
#include <iostream>
enum class Tag
{
A,
B,
C
};
class Foo
{
public:
friend class FooFactory;
const Tag tag;
const std::string string;
private:
Foo(Tag tag, std::string string):
tag {tag}, string {string}
{};
};
class FooFactory
{
public:
static Foo A()
{
return Foo(Tag::A, {"This is string A"});
}
static Foo B()
{
return Foo(Tag::B, {"This is string A"});
}
};
Foo make_Foo(Tag tag)
{
switch(tag)
{
case Tag::A: return FooFactory::A();
case Tag::B: return FooFactory::B();
default: throw std::runtime_error("Called with invalid Tag.");
}
}
class Bar
{
public:
std::string another_string;
const Foo foo;
Bar(Tag tag, std::string another_string):
another_string {another_string}, foo {make_Foo(tag)}
{};
};
int main()
{
Tag tag = Tag::C;
Bar bar(tag, "This is a string");
std::cout << "bar constructed" << std::endl;
}
Foo
我希望在构造时抛出异常Tag::C
,但未实现。上面的代码抛出了这个异常,但是 Valgrind Memcheck 说在这种情况下存在内存泄漏。
经过进一步调查,我发现即使在传递bar.foo
时不是由工厂创建的,但仍然初始化为 unknown和 empty 。这是在这种情况下泄漏的内存吗?抛出异常时如何避免这种情况发生?Tag::C
bar.foo
Tag
std::string
附言。实际上Foo
是一个非类型模板类,而对于Tag::C
,使用了另一个模板参数。这就是为什么我需要标签调度。
解决方案
由于程序过早终止,可能存在“内存泄漏”。为了执行所有析构函数并释放内存,您不能允许异常转义main
函数(或以其他方式调用std::abort
或以其他方式导致引发终端信号)。
具有静态持续时间的对象在主返回后被销毁,并且如果进程终止,则不会发生这种静态对象的清理。此类静态对象可能已分配动态内存,如果不销毁静态对象,则可能会泄漏。即使您不这样做,标准库也可能使用具有静态存储的对象。例如,std::cout
对象。
推荐阅读
- mysql - 想要定位旧数据库
- python - AWS Lambda 中的 PyMySql - 对等点重置连接
- sql - Oracle - 将行转入列
- javascript - 如果条件正确,则在按键上执行功能
- javascript - 开机过程进度条模拟
- c++ - Eclipse/Netbeans 中的处理模型
- php - Eloquent 无法保存新对象:缺少 Illuminate\Database\Eloquent\Model::setAttribute() 的参数 2
- c - 如何在其他循环中使用 k-loop 解决这个问题
- css - 收缩
兄弟姐妹并保持响应 - reactjs - Material-UI - 单击菜单按钮打开所有可用的菜单项