有趣的C++依赖注入方案

Interesting C++ dependency injection scheme

本文关键字:注入 方案 依赖 C++      更新时间:2023-10-16

背景:我是C++的新手。我有一个C#项目,我想将其转换为C++,以便在编写一些有用的C++代码方面获得一些经验,而不仅仅是课本上的例子。为此,我检查了一些开源项目的代码,以获得真实C++的感觉,并尝试在一个相当旧的项目中进行一些重构,在调试构建中使用一些valgrind操作和一些ad-hoc统计数据来确认正确性(所有这些都有真实的输入)。(几年前,我用C++做过一个大学项目,但我不认为这是真正的经验)。

实际问题:

我试图转换为C++的C#项目使用了轻量级依赖注入。每个类都在构造函数中接收一个"上下文"对象。在查询自己的依赖关系之前,它首先将自己插入"上下文"中,这样循环依赖关系就不会成为问题。

经过一番思考,我想出了一个用C++编写的方案。每个DI对象都通过构造函数中的引用接收其依赖项。我在一个类中创建所有DI对象字段(按值作为子对象),并将它们连接到初始化列表中。

// Yes, the project is compiler for a toy programming language
class Compiler {
Logger log;
Options options;
ParserDriver parserDriver;
DeclarationAnalysis declarationAnalysis;
CodeTypeAnalysis codeTypeAnalysis;
FlowAnalysis flowAnalysis;
CodeGeneration codeGeneration;
Check check;
Typings typings;
Operators operators;
Symtab symtab;
public:
Compiler();
};
Compiler::Compiler() :
log(),
options(),
parserDriver(log),
declarationAnalysis(log, symtab, check),
codeTypeAnalysis(log, symtab, operators, typings, check),
flowAnalysis(log),
codeGeneration(typings, symtab),
check(log, symtab),
typings(symtab),
operators(symtab, log, typings),
symtab()
{}
// Example DI object
class DeclarationAnalysis {
Logger* log;
Symtab* symtab;
Check* check;
public:
DeclarationAnalysis(Logger&, Symtab&, Check&);
}
DeclarationAnalysis::DeclarationAnalysis(Logger& log, Symtab& symtab, Check& chack) 
: log(&log), symtab(&symtab), check(&check) {}

这样的代码是否正确,因为它是安全的,没有未定义的行为(例如,symtab是最后初始化的,但作为参数提供给其他字段的构造函数)?乍一看很优雅。内存是打包的,甚至可以在堆栈上分配。我是否重新发现了现有的模式?

构造函数初始化列表是按对象在类中存在的顺序调用的。如果构造函数列表的顺序不同,则可以将编译器设置为warn。打开它。

您可以获取对未初始化值的引用并将其传递。除了存储指向那些未初始化对象的指针或引用之外,任何其他操作都不是一个好计划。

在示例代码中,您只存储指针。这是安全的。

这些类型的析构函数不能假设指向的对象存在,因为在Compiler构造的过程中,它可能会失败(通过异常),并导致已经构造的子对象的破坏。这很难纠正。