【发布时间】:2020-12-12 23:21:36
【问题描述】:
我在测试代码中遇到了一个错误,我必须测试位于钻石遗产底部的一个类,最重要的是,它与另一个类形成了循环依赖,太难改变了(我保证不是我的代码...)。
类 A 的构造函数请求对类 B 的引用,类 B 请求对类 A 的 shared_ptr...
出于单元测试的目的,我想通过为 A 分配内存但不构建实例来打破这种依赖关系。然后通过将此 shared_ptr 传递给 B,一旦 B 被构建,通过构建 A 实例,其构造函数将引用 B。
我成功地在示例代码中重现了该问题,您可以在本地或任何在线编译器中执行:
#include <iostream>
#include <memory>
using namespace std;
struct ILevel_0
{
virtual ~ILevel_0() = 0;
};
ILevel_0::~ILevel_0() {}
struct Level_1_A : virtual ILevel_0
{
int a;
};
struct Level_1_B : virtual ILevel_0
{
int b;
};
struct Level_2 : Level_1_A, Level_1_B
{
int c;
};
struct OtherStruct
{
OtherStruct(const std::shared_ptr<ILevel_0>& lev) : _lev(lev) {}
std::shared_ptr<ILevel_0> _lev;
};
int main()
{
std::shared_ptr<Level_2> level2;
void* level2_rawMemory = operator new(sizeof(Level_2));
Level_2* level2Ptr = static_cast<Level_2*>(level2_rawMemory);
level2.reset(level2Ptr);
std::cout << "------ 1" << std::endl;
std::shared_ptr<ILevel_0> level0 = level2; // OK
std::cout << "------ 2" << std::endl;
// OtherStruct otherStruct(level2); // KO : crash after ------ 1
std::cout << "------ 3" << std::endl;
// Needed, else the shared_ptr's deleter would crash by calling the delete instruction
new (level2.get()) Level_2{};
std::cout << "------ 4" << std::endl;
return 0;
}
可以看到一行(构建一个OtherStruct实例)被注释掉了,这样代码代码就可以编译运行而不会崩溃。如果取消注释,程序将崩溃,不打印“----- 2”。我不明白为什么,也不明白为什么前面的指令(level0建设)没有崩溃。
感谢您的帮助,对于粗略的英语表示抱歉。
【问题讨论】:
-
代码 segvs 对我来说甚至 没有 取消注释该行。这意味着您已经处于未定义的行为世界中,因此恕我直言,搜索注释行有什么问题是毫无意义的,因为其余所有内容都有问题。
-
您可以在移动到下一行之前刷新
std::cout以打印所有输出 -
@fdermishin,我想
std::endlis already flushing。 -
当程序包含未定义的行为时,解释为什么会得到意外结果是没有意义的。此外,几乎没有正当理由直接致电
operator new。
标签: c++ shared-ptr new-operator diamond-problem