不安全。裸指针在构造函数中new易致内存泄漏或悬空指针,异常、拷贝/移动时析构可能不执行;应优先用std::unique_ptr等智能指针自动管理生命周期。

构造函数里直接 new 成员指针是否安全
不安全,除非你明确管理生命周期。C++ 中用裸指针(int*、MyClass*)在构造函数里 new,会立刻引入内存泄漏或悬空指针风险——尤其当构造中途抛异常、或对象被复制/移动时,析构函数可能根本没机会运行。
常见错误现象:std::bad_alloc 抛出后对象处于半构造状态,delete 无从谈起;拷贝构造未定义导致浅拷贝,两个对象指向同一块内存,析构两次就 double free。
- 只在确实需要动态分配、且能严格控制所有权时才用裸指针 +
new - 优先考虑
std::unique_ptr或std::shared_ptr,它们在构造失败时自动释放资源 - 若必须用裸指针,务必在构造函数体末尾前完成初始化,并在析构函数中配对
delete,且显式禁用拷贝(= delete)
用 std::unique_ptr 在构造函数中初始化成员指针
std::unique_ptr 是最常用、最推荐的替代方案:它把堆内存的所有权绑定到对象生命周期,自动 delete,支持移动语义,且能直接在成员初始化列表中构造。
示例:
class Widget {
std::unique_ptr<int> data_;
public:
Widget(int value) : data_(std::make_unique<int>(value)) {} // ✅ 推荐:初始化列表中完成
// 或 Widget(int value) : data_(std::unique_ptr<int>(new int(value))) {} // ⚠️ 不推荐:new 可能抛异常,make_unique 更安全
};</int></int></int>
-
std::make_unique是首选,它比new+ 构造更安全:先分配内存再构造,异常时自动清理 - 不能在初始化列表中写
data_(new int(value))—— 若new成功但后续成员初始化失败,data_已泄露 - 如果构造函数有多个参数需转发给指针所指类型,
std::make_unique<t>(a, b, c)</t>支持完美转发
为什么不能在构造函数体内赋值裸指针
在构造函数体内部用 data_ = new int(value); 看似可行,但违反 RAII 原则,且容易遗漏异常安全路径。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
典型问题:
- 成员变量默认初始化为
nullptr,但中间状态不可靠:若new失败抛std::bad_alloc,对象已部分构造,析构函数不会调用,data_仍为nullptr,看似“干净”,实则掩盖了资源申请失败的事实 - 若类有多个指针成员,其中一个
new成功、下一个失败,前面成功的内存无法回滚 - 拷贝/移动操作完全失控,除非你重写全部特殊成员函数
对比:用 std::unique_ptr 就不存在这个问题——它在初始化列表中构造失败时,自身析构会清理已构造的部分(包括之前成功构造的其他 unique_ptr 成员)。
成员是 const 指针或引用时怎么初始化
如果成员声明为 const MyClass* 或 MyClass&,它必须在初始化列表中绑定,不能等到函数体内。
例如:
class Holder {
const std::string* name_;
public:
Holder(const std::string& s) : name_(&s) {} // ⚠️ 危险:s 是临时对象或栈变量,外部生命周期结束即悬空
// 正确做法:确保所指对象生命周期 >= Holder
Holder(const std::string* p) : name_(p) {} // ✅ 调用方负责保证 p 有效
};
-
const T*本身可为空,但绑定后不能改指向;初始化列表是唯一赋值点 - 绝对不要把局部变量地址或临时对象地址存进成员指针,这是典型的悬空指针
- 若想持有数据副本,用
std::unique_ptr<t></t>或直接存值(T),而非const T*
真正难的不是语法,是所有权归属的判断——谁 new,谁 delete;谁持有,谁负责。哪怕用了 unique_ptr,如果把它 move 给外部作用域,当前对象就不再拥有它。这点常被忽略。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










