You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++中Obj与Obj*的区别及适用场景,Person映射容器选型咨询

在C++中 Obj 与 Obj* 的区别及使用场景,附你的Person结构体分析

嘿,我来帮你理清这个C++里的核心问题,先从Obj和Obj*的本质区别说起,再结合你的Person结构体和map的场景具体分析~

一、Obj 和 Obj* 的核心区别

  • Obj 是实实在在的对象本身:它是值类型,存储在栈(局部变量)或分配的内存块(类成员)里。创建时直接调用构造函数初始化整个对象,赋值时是深拷贝(除非你自定义了移动/拷贝逻辑),销毁时自动调用析构函数,不用你操心内存。
  • Obj* 只是个“地址标签”:它是指针类型,本身只占4/8字节(取决于系统位数),存储的是某个Obj对象的内存地址。赋值时只是拷贝地址,不会复制对象本身;销毁指针的时候,不会自动销毁它指向的对象(裸指针的话,你得手动delete,不然会内存泄漏)。

二、怎么判断该用哪一种?

优先选 Obj 的情况

  • 对象生命周期和当前作用域绑定,不需要在多个地方共享,比如临时变量、简单的类成员。
  • 想避免指针的空指针、野指针风险,或者希望自动管理对象生命周期的时候。
  • 对象体积小,拷贝成本低,值传递/存储更简单直观。

必须用 Obj*(或智能指针)的情况

  • 需要共享对象:比如你的Person结构体里,父母和孩子要指向同一个人,用指针才能让多个对象操作同一个实例,避免拷贝导致的数据不一致。
  • 动态控制生命周期:比如对象需要在堆上创建,生命周期超过当前作用域(比如要在函数外继续使用)。
  • 处理多态:如果Obj是基类,要指向派生类对象,必须用指针(或引用)才能触发多态调用。
  • 对象太大拷贝成本高,或者不可拷贝:比如含有std::unique_ptr这类不可拷贝成员的对象,只能用指针传递/存储。

三、针对你的Person结构体和Personmap的选择

先看你的结构体:

struct Person {
    std::string id_ = NO_ID;
    int height_ = NO_HEIGHT;
    std::vector<Person*> parents_{nullptr, nullptr};
    std::vector<Person*> children_;
};
using Personmap = std::map<std::string, Person>;

核心问题:你的Person有双向引用关系(父母↔孩子),存储Person值类型会踩坑!

如果map存的是Person(值),会出现这些问题:

  1. 引用失效:map内部会自动排序/重新平衡,当你插入新元素时,已有的Person对象可能会被移动内存位置,这时候其他Person里指向它的指针就变成了野指针,访问会直接崩溃或出现未定义行为。
  2. 数据不一致:每次你从map里取Person,拿到的是拷贝,修改这个拷贝不会影响原对象;而且每个拷贝的parents_和children_都是独立的,根本构建不出正确的家族关系。

正确的选择:存储智能指针(优先推荐 std::shared_ptr)

把Personmap改成std::map<std::string, std::shared_ptr<Person>>,原因如下:

  • 自动管理内存:shared_ptr会记录引用次数,当没有任何指针指向对象时,自动调用delete,避免内存泄漏。
  • 保证引用有效:只要shared_ptr存在,对象的内存就不会被释放,其他指针(或shared_ptr)指向它时永远有效。
  • 解决循环引用:因为父母和孩子互相指向,用shared_ptr会导致循环引用(计数永远不为0,对象无法销毁),这时候可以把其中一方改成std::weak_ptr,比如孩子的parents_用weak_ptr<Person>,既能访问父母对象,又不会增加引用计数。

举个简单的实现例子:

#include <memory>
#include <map>
#include <string>
#include <vector>

const std::string NO_ID = "";
const int NO_HEIGHT = 0;

struct Person {
    std::string id_ = NO_ID;
    int height_ = NO_HEIGHT;
    std::vector<std::weak_ptr<Person>> parents_; // 用weak_ptr避免循环引用
    std::vector<std::shared_ptr<Person>> children_;
};

using Personmap = std::map<std::string, std::shared_ptr<Person>>;

int main() {
    Personmap people;

    // 创建Alice并加入map
    auto alice = std::make_shared<Person>();
    alice->id_ = "Alice";
    alice->height_ = 165;
    people["Alice"] = alice;

    // 创建Bob,把Alice设为父母
    auto bob = std::make_shared<Person>();
    bob->id_ = "Bob";
    bob->height_ = 180;
    bob->parents_.push_back(alice); // weak_ptr可以从shared_ptr直接构造
    people["Bob"] = bob;

    // 把Bob加入Alice的孩子列表
    alice->children_.push_back(bob);
}

为什么不推荐裸指针Person*?

裸指针需要你手动new创建、delete销毁,很容易遗漏delete导致内存泄漏,或者在对象被销毁后还有指针指向它(野指针)。智能指针能帮你自动处理这些细节,代码更安全、更易维护。

内容的提问来源于stack exchange,提问作者Grak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:27:45