据我了解RAII习惯用法应用于类所需的资源(如果我错了请纠正我),需要资源的类应定义相应类型的成员,其析构函数将在使用类实例被销毁时自动调用,如下所示:
class Skybox
{
public:
Skybox() : tex_(...) {}
private:
Texture tex_;
};
除了使用智能指针在堆上分配资源之外,如果资源成员在资源初始化之前需要在Skybox
构造函数中执行某些代码,那么如何应用此模式?例如:
class Skybox
{
public:
Skybox(const std::string& fileName);
private:
Texture tex_;
}
Skybox::Skybox(const std::string& fileName)
{
// read stuff from skybox initialization file
// including various texture parameters such as texture file
...
// initialize tex_ based on information read above
}
更新:Texture
类要求在其构造函数中执行所有初始化(即没有Texture::Init()
方法可用)
答案 0 :(得分:10)
将初始化代码包装到函数中,并使用该函数(成员或非成员,静态或非静态,视情况而定)初始化成员变量:
Texture Skybox::init_tex(std::string const& fileName) {
// read stuff from file, including textureFile
// initialize result
return Texture(...);
}
Skybox::Skybox(std::string const& fileName):
tex_(init_tex(fileName))
{ }
初始化函数应该是一个静态函数。如果不是,请注意不要使用尚未初始化的任何成员 - 您在尚未完全初始化的init_tex
实例上调用Skybox
。
答案 1 :(得分:2)
也许您应该将纹理的创建封装到自由函数中,因为文件的读取似乎与Skybox无关,并且可能在其他地方有用。我想其他名称是Factory
。
Tex tex_from_file(const std::string&) {
// ...
}
class Skybox {
Skybox(const std::string& s) : tex_(tex_from_file(s)) {}
};
更好的是来自Tex
的Skybox可构造
宾语。但是,这需要复制或移动Tex
构造的。如果不是这种情况,可以采取适当的解决方法
返回std::unique_ptr<Tex>
。
答案 2 :(得分:0)
使用C ++ 11功能(可变参数模板和完美转发),这可以通过模板构造函数实现:
#include <utility>
template<class T>
class raii_wrapper
{
public:
template<typename... Arg>
raii_wrapper(Arg&&... args) : obj(std::forward<Arg>(args)...) {}
private:
T obj;
};
struct foo
{
foo(){}
};
struct foo_1
{
foo_1(int){}
};
struct foo_2
{
foo_2(int,int&){}
};
int main()
{
raii_wrapper<foo> f;
raii_wrapper<foo_1> f1(1);
int i(3);
raii_wrapper<foo_2> f2(1,i);
return 0;
}
在C ++ 03/98中,模板构造函数仍然是解决方案(但是boost应该有助于可变参数模板和参数传递)。请参阅make_share_ptr等函数的实现。
答案 3 :(得分:0)
如果Texture
类具有默认构造函数并支持交换,则可以使用局部变量初始化资源,并在构造函数的末尾交换它。
Skybox::Skybox(const std::string& fileName)
{
Texture localTex(fileName);
//...
tex_.swap(localTex);
}