我必须从抽象基类 Base 派生类 Derived1 和 Derived2。我还有一个 Container 类,其中包含指向基类对象的唯一指针的映射,因为我想要执行运行时多态性。 Container 类有一个函数“add”,它采用指向基类对象的唯一指针并将其添加到映射中。我注意到我经常知道所添加对象的具体类型,因此我添加了一个重载的模板化 add 函数,该函数按值获取任意对象,将其移动到唯一的指针中并调用另一个 add 函数。 这是一个最小的例子:
#include <map>
#include <memory>
#include <string>
class Base {
public:
virtual ~Base();
};
class Derived1 : Base {
};
class Derived2 : Base {
};
class Container {
public:
std::map<std::string, std::unique_ptr<Base>> coll;
void add(std::string name, std::unique_ptr<Base> elem) {
coll.emplace(name, std::move(elem));
}
template<typename T>
void add(std::string name, T elem) {
this->add(name, std::make_unique<T>(std::move(elem)));
}
};
int main() {
Container c;
//a little more convenient than c.add("1", std::make_unique<Derived1>());
c.add("1", Derived1());
}
当尝试用 clang 16 编译它时,它似乎被卡住了,并且慢慢地使用越来越多的 RAM,直到我的 32GB 已满。 gcc 似乎也被卡住了,但没有使用越来越多的 RAM。
我可以通过重命名其中一个添加函数来修复它,但我仍然很好奇这里发生了什么。
这是预期的行为吗?因为我违反了一些你必须知道的不祥的 C++ 规则?我认为无论输入如何,编译器陷入困境都是不应该真正发生的事情。
因此,要么我做了一些在其他代码库中不会发生的事情,所以这个编译器错误从未被注意到,要么我做了一些非常不寻常的事情,以至于除了编译器被卡住之外,没有人费心去制定一个更干净的解决方案。这是我的第二个问题:他们是否认为我的方法如此不惯用,以至于这对其他人来说似乎不成问题?
该方法模板:
template<typename T>
void add(std::string name, T elem) {
this->add(name, std::make_unique<T>(std::move(elem)));
}
导致实例化的无限循环。
称为首字母缩写
T
=Derived1
,T
=std::uqniue_ptr<Derived1>
,T
=std::uqniue_ptr<std::unique_ptr<Derived1>>
,编译器不断实例化这些不同的方法,直到最终耗尽内存。