Effective C++ 条款 28:避免返回 handles 指向对象内部成分

条款 28:避免返回 handles 指向对象内部成分


核心思想

  1. 封装性
    避免返回 handle(如指针、引用、迭代器等)指向对象内部,能够更好地保护对象的实现细节。

  2. 行为一致性
    保护 const 成员函数的行为使其符合预期,即不能修改对象状态。

  3. 防止悬空句柄
    避免返回指向内部数据的句柄,能够减少悬空句柄的发生。


不推荐的设计

class Point {
public:
    int& x() { return x_; } // 返回引用,暴露内部数据
    int& y() { return y_; }

private:
    int x_, y_;
};

void test() {
    Point p;
    p.x() = 5; // 修改了 Point 内部的 x_
}

这种设计允许外部代码直接修改对象内部数据,破坏了封装性,并可能导致意外错误。


推荐的替代设计

  1. 返回值传递
    如果确实需要暴露内部数据,考虑返回值传递,而非引用或指针。
class Point {
public:
    int x() const { return x_; } // 返回值传递,不暴露内部数据
    int y() const { return y_; }

private:
    int x_, y_;
};

void test() {
    Point p;
    int x = p.x(); // 获取 x 的副本
}
  1. 提供操作接口
    替代返回 handle 的方式,可以提供接口函数,完成需要的操作。
class Point {
public:
    void setX(int value) { x_ = value; } // 提供接口完成修改
    void setY(int value) { y_ = value; }

    int x() const { return x_; }
    int y() const { return y_; }

private:
    int x_, y_;
};

void test() {
    Point p;
    p.setX(5); // 通过接口修改 x_
}
  1. 返回只读 handle
    如果必须返回 handle,确保它是只读的,避免外部代码对内部数据进行修改。
class Point {
public:
    const int& x() const { return x_; } // 返回 const 引用,只读
    const int& y() const { return y_; }

private:
    int x_, y_;
};

void test() {
    Point p;
    const int& x = p.x(); // 获取 x 的只读引用
}

防止悬空句柄的建议

当对象的内部数据可能失效时,返回句柄尤其危险。例如:

class Widget {
public:
    const std::string& name() const { return name_; }
    void setName(const std::string& newName) { name_ = newName; }

private:
    std::string name_;
};

void test() {
    Widget w;
    const std::string& n = w.name();
    w.setName("newName"); // 修改后 n 成为悬空句柄
}

为避免这种问题:

  1. 避免直接返回引用,改为返回值传递。
  2. 设计 API 时避免内存共享副作用,例如使用智能指针或其他封装手段。

总结

  1. 避免返回 handle 指向对象内部成分,保护封装性。
  2. 使用返回值传递或提供操作接口替代直接暴露内部数据。
  3. 如果必须返回句柄,应确保它是只读的,且不会导致悬空句柄。

通过遵循这些原则,可以提高代码的健壮性和可维护性,同时降低错误发生的概率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值