这是另一个问题,“我的代码不起作用,我不知道为什么”,我很害怕。我只是没有足够的 stl 知识来知道为什么 std::map::insert 会抛出异常。如果您知道它在哪些情况下会引发异常,您可能可以跳过这堵文字墙并直接回答。如果您只是迫切需要有关该问题的一些背景知识,那就去做吧。我将发布我的代码并解释做了什么,如果所有对 stl 有更好了解的人都可以解释我的插入调用可能有什么问题,我将不胜感激。
不久前我写了一个对象,我偶尔将它用作我的去工厂对象。它的主要目的基本上是获取一个字符串并存储该字符串和一个“创建新对象函数”指针,这样最后你就可以调用一个函数,传递一个字符串,如果它有一个有效的注册,它返回派生对象的新实例。少说话,多代码,这就是我得到的:
工厂.h
#ifndef FACTORY_H
#define FACTORY_H
// library tools
#include <map>
#include <string>
// Simplified registration macros
#define DECLARE_DERIVED(T, base) static Factory<base>::DerivedRegister<T> reg;
#define DEFINE_DERIVED(T, base, s) Factory<base>::DerivedRegister<T> T::reg(s);
template<class base>
class Factory
{
protected:
template<class T>
static base * createT() { return new T;}
public:
typedef std::map<std::string, base*(*)()> map_type;
virtual ~Factory(){ }
static base * createInstance(const std::string & s)
{
if(!m_Map.count(s))
return nullptr;
std::map<std::string, base*(*)()>::iterator it = m_Map.find(s);
return it->second();
}
template <class T>
struct DerivedRegister;
protected:
static map_type m_Map;
};
template<class base>
template<class T>
struct Factory<base>::DerivedRegister : public Factory<base>
{
DerivedRegister(std::string const & s)
{
m_Map.insert(std::pair<std::string, base*(*)()>(s, &createT<T>));
}
};
#endif
这里有一个更好的解释它真正快速地做什么。假设您有一个基类 A 类。然后你有任意数量的派生类。我在某处模板化为 A 的工厂对象,然后手动创建派生寄存器对象,或使用派生类声明顶部的宏来创建静态注册表对象。然后在实现中定义它并调用它的构造函数,传入一个用于标识对象的字符串。使用工厂成员 createInstance,您可以传入一个字符串标识符并返回一个由 A * 指向的派生对象。
例子:
啊
class A
{
};
A.cpp
// the map for this factory template has to be defined somewhere, as it is static
Factory<A>::map_type Factory<A>::m_Map;
bh
#include <A.h>
class B : public A
{
// anywhere in declaration of derived B
DECLARE_DERIVED(A, B)
};
b.cpp
// just somewhere in cpp file
DEFINE_DERIVED(A, B, "B")
主文件
int main()
{
A * ptr;
Factory<A> factory;
ptr = factory.createInstance("B");
}
这个对象过去曾为我工作过,大部分都没有问题。现在我正在做一个更复杂的项目。我喜欢游戏引擎所涉及的数据组织/api设计,我只是想实现一个编目解决方案,(但不是实例化的)着色器,这样你就有了一个完整的着色器列表。已经编程,但除非需要,否则它们不会在运行时实例化。除此之外,这个问题实际上与 d3d11 无关,或者至少我希望不是。
这就是正在发生的事情。我有一个代表图形着色器抽象类的对象。您希望编写的所有着色器都必须从该对象派生。您从所有不同的着色器中派生并实现它的功能不同。
让我们在命名空间同步中调用基础对象“SYNC::D3D11Shader”以及派生着色器“ColorShader”、“LightShader”和“TextureShader”。由于我不只是想在渲染对象中创建这些着色器实例的 std::map,因此我在渲染对象中创建了一个工厂,就像这样。
D3D11Renderer.h
class D3D11Renderer
{
// many other members...
Factory<D3D11Shader> m_ShaderFactory;
// many other member...
};
D3D11Renderer.cpp
// define this templated classes map or you'll get undefined errors
Factory<SYNC::D3D11Shader>::map_type Factory<SYNC::D3D11Shader>::m_Map;
然后在 ColorShader 中我使用这样的宏
D3D11ColorShader.h
class D3D11ColorShader : public SYNC::D3D11Shader
{
// ...lotsa members
DECLARE_DERIVED(D3D11ColorShader, SYNC::D3D11Shader)
// lotsa member...
};
D3D11ColorShader.cpp
// define the registery object with it's key here
DEFINE_DERIVED(D3D11ColorShader, SYNC::D3D11Shader, "ColorShader")
这一切都编译得很好,它抛出异常的地方是我第一次在 D3D11ColorShader.cpp 中调用 registryObjects 构造函数,特别是在插入调用时。异常错误是这样的:
Syncopate.exe 中 0x772315de 处的未处理异常:0xC0000005:访问冲突读取位置 0x00000004。
所以实际上,问题归结为 std::map::insert 何时抛出异常以及为什么。我只知道每个人都会询问我正在做的事情的背景。低头,一堵巨大的文字墙出现了!我真正需要的只是一种预感。
我应该还是不应该标记 d3d11,因为这个问题与它无关?