首页 > 解决方案 > 可以把这个传给会员吗?

问题描述

我有一堂课Data。该类包含 2 个(或更多)类实例OtherData。现在,OtherData(作为成员存储在 class 中Data)的每个实例都有一些共同的数据。我不希望每个实例OtherData都拥有它们共有的数据的副本。例如,OtherData可以共享一个类型为 的对象CommonData

现在,我决定将通用数据存储在Data类中。在构造时,实例OtherData将接收指向Data实例的指针,以便能够访问公共数据。我决定这样做是为了避免类的实现CommonData。它似乎更容易和更短。

一个简短的例子:

// the class which contains the common data as well as the instances of OtherData
struct Data;

struct OtherData
{
    OtherData(const Data* data) : _data { data } {}
    const Data* _data;
    int getCommonData() const;
};

struct Data
{
    Data() : _data1 { this }, _data2 { this } {}
    Data(const Data&) = delete;
    Data(Data&&) = delete;
    Data& operator=(const Data&) = delete;
    Data& operator=(Data&&) = delete;
    OtherData _data1, _data2;
    int getData() const { return 1; }
};

int OtherData::getCommonData() const  { return _data->getData(); }

现在,从 的实例中OtherData,我可以很容易地获取公共数据。

我通常避免传递this给成员,我讨厌循环依赖(我的意思是一个包含另一个对象的对象,而后者具有指向前者的引用或指针)。然而,它看起来很容易,我无法证明这是一个糟糕的设计。

所以,我的问题是:你会避免这样的设计,为什么?还是你觉得可以接受?

标签: c++

解决方案


这是一个脆弱的设计。复制或移动初始Data对象(例如按值作为参数传递)对象,您就会遇到混乱。

Data选项 A:禁用对象的复制和移动

处理此问题的一种方法是禁用复制和移动。一旦Data创建了一个对象,它就不能被复制或移动,从而确保其中的指针OtherData保持有效。这是一个快速的解决方案,但非常有限制,但是在一些非常具体的场景中它是可以接受的。

struct Data
{
     Data() { /* .. */ }

     Data(const Data&) = delete;
     Data(Data&&) = delete;
     Data& operator=(const Data&) = delete;
     Data& operator=(Data&&) = delete;
};

选项 B:使用智能指针

每当您处理需要从多个对象访问的资源时,请考虑实现 RAII 的智能指针。unique_ptr现在你必须在和之间做出选择shared_ptr。如果CommonData需要和对象一样长寿命Data(没有OtherData寿命Data)那么你可以使用unique_ptr,否则你需要shared_ptr

使用示例unique_ptr

#include <memory>

struct CommonData
{
    int a;

    CommonData(int a) : a{a} {}
};

struct Data;

struct OtherData
{
    OtherData(const CommonData* common_data) : _common_data { common_data } {}
    const CommonData* _common_data;
    int getCommonData() const;
};

struct Data
{
    Data()
        : _common_data{std::make_unique<CommonData>(1) },
        _data1 { _common_data.get() },
        _data2 {  _common_data.get() }
    {}

    // this field must be declared before any `OtherData` fields
    std::unique_ptr<CommonData> _common_data;
    OtherData _data1, _data2;
};

int OtherData::getCommonData() const  { return _common_data->a; }

推荐阅读