存储指向静态变量的指针



我已经为c ++创建了一个单元测试框架,我想稍后将其移植到C,但我遇到了单元测试根本无法运行的问题。单元测试是在.cpp文件中创建的,只有一个.cpp文件应运行所有测试。

为了简化一点,以下是通常创建测试的方式:

主.cpp

#define UNIT_TEST_IMPL // or whatever
#include "unit_test.hpp"
int main()
{
for(const auto& test : tests_queue)
test->run();
return 0;
}

unit_test.hpp

#pragma once
struct Base
{
protected:
Base() = delete;
Base(Base* ptr);
public:
virtual void run() = 0;
};
#if defined(UNIT_TEST_IMPL)
#include <vector>
std::vector<Base*> tests_queue;
Base::Base(Base* ptr)
{
tests_queue.push_back(ptr);
}
#endif

测试.cpp

#include "unit_test.hpp"
#include <iostream>
struct Test : Base
{
Test()
: Base(this)
{}
void run() override
{
std::cout << "new test" << std::endl;
}
};
struct Test2 : Base
{
Test2()
: Base(this)
{}
void run() override
{
std::cout << "new test2" << std::endl;
}
};
static Test test;
static Test2 test2;

问题是:为什么它不运行测试中定义的测试.cpp(如果我在 main.cpp 文件中创建测试,它们运行得很好(?我的猜测是问题在于我存储 Base 指针的方式,但我不知道。 编译器是 g++ 6.4.0

静态初始化订单惨败在行动:

跨翻译单元的全局初始化顺序是未指定的,因此如果testtest2tests_queue之前实例化,则后面的初始化将破坏注册。

一种可能的更正:

#pragma once
struct Base
{
protected:
Base();
public:
virtual ~Base() = default;
virtual void run() = 0;
};
#if defined(UNIT_TEST_IMPL) // Should be defined only once.
#include <vector>
std::vector<Base*>& get_tests_queue()
{
static std::vector<Base*> tests_queue;
return tests_queue;
}
Base::Base()
{
get_tests_queue().push_back(this);
}
#endif

所以你的主要.cpp将是:

#define UNIT_TEST_IMPL // or whatever
#include "unit_test.hpp"
int main()
{
for(const auto& test : get_tests_queue())
test->run();
}

您的单元测试将不被修改:

#include "unit_test.hpp"
#include <iostream>
struct Test : Base
{
void run() override { std::cout << "new test" << std::endl; }
};
struct Test2 : Base
{
void run() override { std::cout << "new test2" << std::endl; }
};
static Test test;
static Test2 test2;

演示

我的赌注是某种形式的静态初始化惨败

不确定,但你不能指望全局变量(测试中定义的 Test1 和 Test2 变量.cpp被启动为主运行。

根据经验,如果可以的话,请避免使用全局变量(在这种情况下,您可能可以(。

但主要是,你的程序不应该对全局/静态变量的初始化顺序做出任何假设。在这里,您假设两个全局变量在 main 之前初始化。可能,他们不是

相关内容

  • 没有找到相关文章

最新更新