使用unique_ptr替换new/delete时复合类型初始化报错的解决方法
问题分析与解决
错误原因
问题核心在于列表初始化和构造函数调用初始化的语法差异:
- 原new/delete版本中,
new T{std::forward<Args>(args)...}使用花括号的列表初始化,对于Point这类聚合类型(无用户定义构造函数的类),可以直接通过列表为成员变量x和y赋值。 - 而
std::make_unique的内部实现是new T(std::forward<Args>(args)...),即圆括号的构造函数调用初始化。由于Point没有接收两个int参数的构造函数,编译器会尝试把1,2解析为逗号表达式(最终结果为2),进而寻找Point(int)构造函数,自然找不到匹配项,因此报错。
解决方案
方案1:修改dynamic构造逻辑,兼容列表初始化
绕开make_unique的限制,直接构造unique_ptr时用花括号初始化T,既保留自动内存管理,又延续原版本的聚合类型支持:
template <typename T> struct dynamic { explicit dynamic(const T& value = T{}) : ptr(std::unique_ptr<T>(new T{value})) {} template <typename... Args> dynamic(Args&&... args) : ptr(std::unique_ptr<T>(new T{std::forward<Args>(args)...})) {} operator T&() { return *ptr; } T* operator->() { return ptr.get(); } std::unique_ptr<T> ptr; };
方案2:给聚合类型添加构造函数
如果允许修改Point的定义,新增对应构造函数,让make_unique能正常调用构造逻辑:
struct Point { int x; int y; Point(int x_, int y_) : x(x_), y(y_) {} // 新增构造函数 };
此时std::make_unique<Point>(1,2)会直接调用该构造函数,无需依赖列表初始化。
方案3:C++20+直接兼容
C20起通过P0960提案支持聚合类型的括号初始化,若你的编译器开启C20及以上标准,原代码可直接编译通过,无需修改。
修改后完整代码(方案1示例)
#include <iostream> #include <memory> template <typename T> struct dynamic { explicit dynamic(const T& value = T{}) : ptr(std::unique_ptr<T>(new T{value})) {} template <typename... Args> dynamic(Args&&... args) : ptr(std::unique_ptr<T>(new T{std::forward<Args>(args)...})) {} operator T&() { return *ptr; } T* operator->() { return ptr.get(); } std::unique_ptr<T> ptr; }; struct Point { int x; int y; }; int main() { dynamic<int> i = 123; std::cout << i << '\n'; dynamic<Point> p{1, 2}; std::cout << static_cast<Point&>(p).x << ' ' << p->y << '\n'; return 0; }
内容的提问来源于stack exchange,提问作者user1832484
相关产品推荐
相关产品推荐

