我有一个类 Bar
,它有一个 Foo
类型的成员。类 Foo
应该仅在某些固定和恒定状态下构造,这些状态是基于 Tag
进行区分的。由于我不希望在任何其他状态下构造 Foo
,因此我将其构造函数设为私有(private)并实现了一个工厂 FooFactory
。
在 Bar
构造函数的初始值设定项列表中,我调用函数 make_Foo
,该函数根据标签
。
#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;
}
我希望在使用 Tag::C
构造 Foo
时抛出异常,但未实现。上面的代码抛出了这个异常,但是Valgrind Memcheck说这种情况下存在内存泄漏。
经过进一步调查,我发现即使在传递 Tag::C
时 bar.foo
不是由工厂创建的,bar.foo
仍然使用未知的 Tag
和空的 std::string
进行初始化。这是本例中泄漏的内存吗?抛出异常时如何避免这种情况发生?
ps。实际上,Foo
是一个非类型模板类,对于Tag::C
,使用了另一个模板参数。这就是为什么我需要标签调度。
最佳答案
由于程序提前终止,可能会出现“内存泄漏”。为了执行所有析构函数并释放内存,您不得允许异常转义 main
函数(或调用 std::abort
或以其他方式导致终端信号被提高)。
具有静态持续时间的对象将在 main 返回后被销毁,并且如果进程终止,则不会发生静态对象的清理。此类静态对象可能分配了动态内存,如果静态对象未被销毁,则动态内存可能会泄漏。即使您不这样做,标准库也可能使用具有静态存储的对象。例如,std::cout
对象。
关于c++ - 使用标记分派(dispatch)的 const 成员构造函数中的内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53762186/