使用三元运算符创建std::unique_ptr<IDBAbstractFactory>报错,求单行实现方案
我有一个基类接口IDBAbstractFactory,以及两个派生类CPostgreSQLDBAbstractFactory和COracleDBAbstractFactory。尝试用三元运算符直接初始化std::unique_ptr<IDBAbstractFactory>时触发编译错误:
std::unique_ptr<IDBAbstractFactory> up((dbType == DATABASE_NAME::POSTGRES)? new CPostgreSQLDBAbstractFactory : new COracleDBAbstractFactory);
报错信息:
Error (active) E0042 operand types are incompatible ("CPostgreSQLDBAbstractFactory *" and "COracleDBAbstractFactory *")
Error C2446 ':': no conversion from 'COracleDBAbstractFactory *' to 'CPostgreSQLDBAbstractFactory *'
改用if-else先创建基类指针再初始化unique_ptr可以正常运行:
IDBAbstractFactory* pIDBAbstractFactory; if(dbType == DATABASE_NAME::POSTGRES) pIDBAbstractFactory = new CPostgreSQLDBAbstractFactory(); else pIDBAbstractFactory = new COracleDBAbstractFactory(); std::unique_ptr<IDBAbstractFactory> up(pIDBAbstractFactory);
需求:用单行代码实现,且创建静态std::unique_ptr。
原因分析
三元运算符要求两个分支的表达式类型必须一致(或能隐式转换为同一类型)。这里两个分支返回的是同级派生类的指针,无法互相隐式转换,因此编译器报错。而if-else中是直接赋值给基类指针,派生类指针可以隐式转换为基类指针,所以能正常运行。
单行实现方案
方案1:显式转换分支类型为基类指针
将其中一个分支的指针显式转换为基类指针,让两个分支类型统一:
static std::unique_ptr<IDBAbstractFactory> up( dbType == DATABASE_NAME::POSTGRES ? static_cast<IDBAbstractFactory*>(new CPostgreSQLDBAbstractFactory()) : static_cast<IDBAbstractFactory*>(new COracleDBAbstractFactory()) );
方案2:使用std::make_unique(C++14及以上)
利用std::make_unique直接创建基类指针的unique_ptr,统一分支类型:
static std::unique_ptr<IDBAbstractFactory> up = dbType == DATABASE_NAME::POSTGRES ? std::unique_ptr<IDBAbstractFactory>(std::make_unique<CPostgreSQLDBAbstractFactory>()) : std::unique_ptr<IDBAbstractFactory>(std::make_unique<COracleDBAbstractFactory>());
方案3:lambda表达式封装逻辑(C++11及以上)
用lambda封装if-else逻辑,单行完成初始化,同时保证类型正确:
static std::unique_ptr<IDBAbstractFactory> up = []{ return dbType == DATABASE_NAME::POSTGRES ? std::unique_ptr<IDBAbstractFactory>(new CPostgreSQLDBAbstractFactory()) : std::unique_ptr<IDBAbstractFactory>(new COracleDBAbstractFactory()); }();
若支持C++14,可结合std::make_unique简化:
static std::unique_ptr<IDBAbstractFactory> up = []{ return dbType == DATABASE_NAME::POSTGRES ? std::make_unique<CPostgreSQLDBAbstractFactory>() : std::make_unique<COracleDBAbstractFactory>(); }();
补充说明
- 优先使用
std::make_unique或lambda方案,相比直接new更安全,能避免潜在的内存泄漏风险。 - 静态局部变量的初始化在C++11及以后是线程安全的,若为全局静态变量则需注意初始化顺序问题。
内容的提问来源于stack exchange,提问作者Rakesh Mehta

