亲子关系所有权的推荐模式

Recommended pattern for parent child relationship ownership

本文关键字:模式 所有权 关系      更新时间:2023-10-16

我是c++的新手,我试图理解引用计数内存。在下面的代码中,我有两个方法来返回矩形向量

vector<RectangleRef> &rectanglesRef() { return rects_; }
vector<RectangleRef> rectangles() { return rects_; }

我不确定的是,如果他们中的任何一个在堆栈上为调用者创建一个新的向量?

当ClassA在一个向量中包含许多ClassB时,您希望能够公开的推荐模式是什么?

void addRectangle(RectangleRef r) { rects_.push_back(r); }
void removeRectangle(RectangleRef r);
vector<RectangleRef> rectangles() { return rects_; }

或者你只是让调用者访问内部结构并允许他们随意添加/删除东西?

如果Rectangle类要保留指向它所属的Test类的回指针,则使用

typedef std::weak_ptr<Test> TestWeakRef;
...
TestWeakRef test_;

正确的成语?

谢谢你的帮助。

代码:

#include <iostream>
#include <limits>
#include <vector>
using namespace std;
class Point {
public:
    Point() {
        x_ = 0.0;
        y_ = 0.0;
    }
    Point(double x, double y) {
        x_ = x;
        y_ = y;
    }
    double x() const { return x_; }
    double y() const { return y_; }
    void setX(double x) { x_ = x; }
    void setY(double y) { y_ = y; }
    void offset(double dx, double dy) {
        setX(x() + dx);
        setY(y() + dy);
    }
    bool operator == (Point const &point) {
        return x() == point.x() && y() == point.y();
    }
    void operator = (Point const &point) {
        setX(point.x());
        setY(point.y());
    }
private:
    double x_;
    double y_;
};

class Size {
public:
    Size() {
        width_ = 0.0;
        height_ = 0.0;
    }
    Size(double width, double height) {
        width_ = width;
        height_ = height;
    }
    double width() const { return width_; }
    double height() const { return height_; }
    double area() const { return width() * height(); }
    void setWidth(double width) { width_ = width; }
    void setHeight(double height) { height_ = height; }
private:
    double width_, height_;
};
class Rectangle {
public:
    Rectangle() {
        origin_ = Point();
        size_ = Size();
    }
    Rectangle(double x, double y, double width, double height) {
        origin_ = Point(x, y);
        size_ = Size(width, height);
    }
    Point origin() const { return origin_; }
    Size size() const { return size_; }
private:
    Point origin_;
    Size size_;
};
typedef std::shared_ptr<Rectangle> RectangleRef;
typedef std::weak_ptr<Rectangle> RectangleWeakRef;
class Test {
private:
    vector<RectangleRef> rects_;
public:
    Test() {
        rects_ = vector<RectangleRef>();
        for (int i = 0; i < 100; i++) {
            RectangleRef ptr = make_shared<Rectangle>(i*1.0, 0.0, 1.0, 1.0);
            rects_.push_back(ptr);
        }
    }
    vector<RectangleRef> &rectanglesRef() { return rects_; }
    vector<RectangleRef> rectangles() { return rects_; }
};
int main(int argc, const char * argv[]) {
    vector<RectangleRef> r;
    vector<RectangleRef> r1;
    if (true) {
        Test t = Test();
        r = t.rectangles();
        r1 = t.rectanglesRef();
        if (r1 == r) { cout << "they matchn"; }
    }
    // insert code here...
    //std::cout << r->origin().x() << "n";
    return 0;
}

Drew Dormann很好地回答了前几个问题。我只是在添加一些东西。

首先,如果你真的需要共享所有权语义,你应该只使用shared_ptr。引用计数有开销,如果你没有正确分解循环依赖,它会导致内存泄漏,所以除非你真的需要,否则你不应该这么做。

在这段代码中,没有真正的理由说明为什么需要存储vector<RectangleRef>而不是简单的vector<Rectangle>。后者还具有更好的数据局部性,这对于缓存很重要。

其次,这

typedef std::weak_ptr<Test> TestWeakRef;
// ...
TestWeakRef test_;

通常不是一个好主意,因为它约束了Test的生命周期管理策略。也就是说,因为weak_ptr 只能引用由shared_ptr管理的生命周期的对象,所以不可能执行Test t;unique_ptr<Test> t;之类的操作。除非你有一个非常非常好的理由,否则不要这样做。

如果你想要回指针,只需使用一个简单的非拥有原始指针,无论Test对象是在堆栈上还是由unique_ptrshared_ptr或其他自定义智能指针管理,它都可以工作:

Test * test_;

如果Test中存储的Rectangle的生命周期超过了Test的生命周期(这只会发生在你没有独占它们的情况下(例如,将shared_ptr的生命周期存储到它们中),这通常是不必要的),你的Test析构函数可能不得不遍历它存储的Rectangle,并清除指针以防止悬空指针。但是典型的情况是,当对象被销毁时,存储在Test对象中的内容将消失,在这种情况下,这是不必要的。

欢迎使用Stack Overflow!你有几个问题有点乱,但我会尽力的。


我不确定的是,如果他们中的任何一个在堆栈上为调用者创建一个新的向量?

创建一个完整的新向量。

vector<RectangleRef> rectangles() { return rects_; }

这避免了复制。

vector<RectangleRef> &rectanglesRef() { return rects_; }

当ClassA在一个向量中包含许多ClassB时,您希望能够公开的推荐模式是什么?你会……或者你只是让调用者访问内部结构并允许他们随意添加/删除东西?

常见的范例是提供访问器函数,就像您所做的那样。我推荐。

如果矩形类是保持一个回指针的测试类,它属于,是使用std::weak_ptr正确的成语?