如何延迟初始化类成员变量?C++构造器权限与实例声明问题
嘿,这个问题我之前也碰到过——就是想严格控制GlslProgram的构造方式,不让别人随便用默认构造器,但又得在BasicCubeExample里先声明成员变量,等格式明确了再初始化。给你几个靠谱的解决办法:
方案1:用
std::optional延迟初始化(推荐C++17+) 这是最直观也最符合语义的方案,std::optional专门用来表示“可能存在也可能不存在”的对象,默认状态下不会构造内部的GlslProgram:
#include <optional> class BasicCubeExample : public Application { private: virtual void set_info() { Application::set_info(); m_info.title = "Basic cube example"; } // 初始为空,完全不调用GlslProgram的任何构造器 std::optional<GlslProgram> m_shader; // 在合适的时机(比如初始化函数)再构造对象 void init() override { GlslProgram::Format format; format.vertex("path/to/your/vertex.shader"); // 调用目标构造器,直接在optional的内存里构造对象 m_shader.emplace(format); } };
这时候你就可以放心地把GlslProgram的默认构造器删除或者设为私有了:
class GlslProgram { public: // ... 其他成员 ... // 删除默认构造器,禁止外部默认构造 GlslProgram() = delete; GlslProgram(const Format& format, const bool separable = false); // ... 其他成员 ... };
方案2:用智能指针(兼容C++11+)
如果你的项目还在用C++11/14,或者更习惯动态内存管理的方式,std::unique_ptr也是个稳妥的选择:
#include <memory> class BasicCubeExample : public Application { private: virtual void set_info() { Application::set_info(); m_info.title = "Basic cube example"; } // 初始为nullptr,不构造GlslProgram对象 std::unique_ptr<GlslProgram> m_shader; void init() override { GlslProgram::Format format; format.vertex("path/to/your/vertex.shader"); // 动态构造对象,调用目标构造器 m_shader = std::make_unique<GlslProgram>(format); } };
智能指针会自动管理内存,不用手动delete,同样可以删除GlslProgram的默认构造器,因为这里只是声明了指针,并没有构造GlslProgram实例。
方案3:手动内存管理(进阶场景)
如果对内存布局有严格要求(比如不想用动态分配),可以用std::aligned_storage预留内存,之后手动构造和析构对象:
#include <type_traits> class BasicCubeExample : public Application { private: virtual void set_info() { Application::set_info(); m_info.title = "Basic cube example"; } // 预留足够容纳GlslProgram的内存,并保证对齐 typename std::aligned_storage<sizeof(GlslProgram), alignof(GlslProgram)>::type m_shader_storage; GlslProgram* m_shader = nullptr; void init() override { GlslProgram::Format format; format.vertex("path/to/your/vertex.shader"); // 手动在预留内存上构造对象(placement new) m_shader = new (&m_shader_storage) GlslProgram(format); } // 必须手动调用析构函数清理 ~BasicCubeExample() override { if (m_shader != nullptr) { m_shader->~GlslProgram(); } } };
这个方案完全控制对象的生命周期,但代码复杂度高,容易出错,只推荐在对性能或内存布局有特殊要求的场景使用。
内容的提问来源于stack exchange,提问作者Startec
相关产品推荐
相关产品推荐

