简体   繁体   English

如何为数据对象分配const成员?

[英]How do I assign a data object with const members?

Hope this is not a duplicate. 希望这不是重复的。 If so, please point me to it in a comment and I'll remove the question again. 如果是这样,请在评论中将其指向我,我将再次删除该问题。

I have a data object with data that's only valid in a bundle - ie there's no sense in changing the value of one member without invalidating the other members. 我有一个数据对象,其数据仅在捆绑包中有效-即,在不使另一个成员无效的情况下更改一个成员的值是没有意义的。
This data object describes some image information: 此数据对象描述了一些图像信息:

struct ImageInfo
{
    ImageInfo(const double &ppix, ...)
        : PpiX(ppix),
        ...
    { }

    const double PpiX;
    const double PpiY;
    const int SizeX;
    const int SizeY;
};

In my image object I have a non-const member of type ImageInfo : 在我的图像对象中,我具有ImageInfo类型的非常量成员:

class MyImageObject
{
    ...
private:
    ImageInfo mMyInfo;
}

I want to be able to change mMyInfo at runtime, but only so that it will take a new ImageInfo(...) instance. 我希望能够在运行时更改mMyInfo ,但这只是为了使其采用新的ImageInfo(...)实例。

In the MyImageObject::Load() function, I'd like to read this data from the file info and then create an ImageInfo instance with the correct set of data: MyImageObject::Load()函数中,我想从文件信息中读取此数据,然后使用正确的数据集创建一个ImageInfo实例:

double ppix = ImageFile.GetPpiX();
...
mMyInfo = ImageInfo(ppix, ...);

But I couldn't manage to write a valid assignment operator (copy constructor is possible of course). 但是我无法编写一个有效的赋值运算符(当然可以使用复制构造函数)。 My solution left mMyInfo empty, because I didn't reference this : 我的解决方案将mMyInfo空,因为我没有引用this

ImageInfo operator=(const ImageInfo &other)
{
    // no reference to *this
    return ImageInfo(other);
}

Out of curiosity I'd like to know how the assignment operator for such a class would need to look like. 出于好奇,我想知道此类的赋值运算符的外观。

I'm using plain C++. 我正在使用纯C ++。

EDIT 编辑
Possible solutions (the goal is to keep the data transportable, but coherent): 可能的解决方案(目标是保持数据可传输,但保持一致):

  • Use private members together with Get...() functions -> simple, but I'd like to avoid the parentheses. 将私有成员与Get...()函数一起使用->简单,但我想避免使用括号。
  • Store a pointer to ImageInfo: ImageInfo *mpMyInfo; 存储指向ImageInfo *mpMyInfo;的指针: ImageInfo *mpMyInfo; (I'd like to avoid the heap.) (我想避免堆。)
  • Use serialization and store the serialized ImageInfo, then create local instances from the serialized data. 使用序列化并存储序列化的ImageInfo,然后从序列化的数据创建本地实例。

I don't think you can have const member variables that aren't static. 我认为您不能拥有非静态的const成员变量。 If you need const variables that change with the instance, you could do something like this: 如果需要随实例更改的const变量,则可以执行以下操作:

struct ImageInfo
{
private:
    double myPpiX;
    double myPpiY;
    int mySizeX;
    int mySizeY

public:
    ImageInfo(const double &ppix, ...)
        : myPpiX(ppix),
          PpiX(myPpiX),
        ...
    { }

    ImageInfo( const ImageInfo &other)
    : myPpiX( other.myPpiX),
      PpiX(myPpiX)
     ...
    { }

    const double &PpiX;
    const double &PpiY;
    const int &SizeX;
    const int &SizeY;

    // EDIT: explicit assignment operator was missing
    ImageInfo& operator=(const ImageInfo &other)
    {
        myPpiX  = other.myPpiX;
        myPpiY  = other.myPpiX;
        mySizeX = other.mySizeX;
        mySizeX = other.mySizeX;
        return *this;
    }
};

The values are stored in the private variables that can be set at construction, and their values accessed by const references. 这些值存储在可在构造时设置的私有变量中,并且它们的值可通过const引用进行访问。 You're also not dependent on the references passed into the constructor living as long as the ImageInfo instance. 只要ImageInfo实例存在,您也不依赖传递给构造函数的引用。

As they are data fields that can be modified, they are not const . 因为它们是可以修改的数据字段,所以它们不是const

If you want to restrict post-construct access to them to const , you need to wrap them in accessors as follows: 如果要const它们的构造后访问限制为const ,则需要将它们包装在访问器中,如下所示:

struct ImageInfo
{
  ImageInfo(const double &ppix, /*...*/)
    : PpiX_(ppix),
    /*...*/
  { }
  double const& PpiX() const {return PpiX_; };
  double const& PpiY() const {return PipY_; };
  int const& SizeX() const {return SizeX_; };
  int const& SizeY() const {return SizeY_; };
private:
  double PpiX_;
  double PpiY_;
  int SizeX_;
  int SizeY_;
};

That allows move/copy assignment and construction, while blocking non- const access outside of said construction. 这使得移动/复制分配和建设,同时阻止非const访问以外的建说。

Avoiding the () is tricky, but could be done with pseudo-references, something like this: 避免使用()很棘手,但是可以使用伪引用来完成,如下所示:

struct pseudo_const_reference_to_Ppix {
  ImageInfo const* self;
  operator double() const { return self->Ppix; }
  void reseat( ImageInfo const* o ) { self = o; }
};

plus a whole pile of boilerplate to overload every const operator on the left and right such that the above pseudo_const_reference_* is just as valid as double . 加上一堆样板来重载左右的每个const运算符,使得上面的pseudo_const_reference_*double一样有效。

Generic versions can be written (either taking a functor or a std::function if you are willing to suffer type erasure overhead). 可以编写通用版本(如果您愿意承担类型擦除的开销,则可以使用函子或std::function )。

Then you maintain these pseudo- const references on assignment and copy/move construction. 然后,您可以在分配和复制/移动构造时维护这些伪const引用。

I think the () is the better option. 我认为()是更好的选择。

Note that the overhead of a pointer (or more) per pseudo-reference is basically unavoidable: member variables do not have access to the this from which they are invoked, even though the accesing site has it right there plain as day. 请注意,每个伪引用的指针(或多个指针)的开销基本上是不可避免的:成员变量无法访问从中调用它们的this ,即使访问站点当天将访问该变量的位置也很简单。

If something is const, you can't change it. 如果某些内容为const,则无法更改。 Full stop. 句号

So you must adjust the design somewhere, either not have those ImageInfo members const, not have ImageInfo as member, or best: not do the assignment. 因此,您必须在某个地方调整设计,要么不具有那些ImageInfo成员const,不具有ImageInfo作为成员,要么最好:不进行分配。

Normally const members are set in constructor. 通常const成员是在构造函数中设置的。 You can make a load function that creates a MyImageObject object with all its content, so avoiding to have a half-done thing and load the sate in a second phase. 您可以创建一个加载函数,以创建一个包含所有内容的MyImageObject对象,这样就避免了事半功倍并在第二阶段加载状态。

An alternative is to have the mMyInfo indirectly, say using unique_ptr, then you can replace it with another instance. 一种替代方法是间接使用mMyInfo,例如使用unique_ptr,然后可以将其替换为另一个实例。 I would not do that without a really good reason. 如果没有充分的理由,我不会这样做。

Immutable value objects are great. 不可变的价值对象很棒。 But the variable holding the value object (mMyInfo in MyImageObject) should be (non-constant) a pointer. 但是保存值对象(MyImageObject中的mMyInfo)的变量应该是(非常数)指针。 In other languages (eg Java) this is automatically the case, but not in C++, where you need the * operator. 在其他语言(例如Java)中,这是自动的情况,但在C ++中则不是这样,您需要*运算符。 Also, there is no need to override/implement the = operator for value objects. 同样,也不需要为值对象重写/实现=运算符。 To change the image data within the image object, you assign a newly constructed ImageInfo object to the myImageInfo pointer. 要更改图像对象内的图像数据,请将新构造的ImageInfo对象分配给myImageInfo指针。 This way, none of the internal variables of the value object are changed. 这样,值对象的内部变量都不会更改。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM