当前位置:  开发笔记 > 编程语言 > 正文

区分对不可变对象和可变对象的const引用

如何解决《区分对不可变对象和可变对象的const引用》经验,为你挑选了2个好方法。

在C++中是否有任何可接受的方法来区分对不可变对象的const引用与可变对象的const引用?

例如

class DataBuffer {
   // ...
};

class Params {
   // ...
};

class C {
public:
    // Given references must be valid during instance lifetime.
    C(const Params& immutableParameters, const DataBuffer& mutableDataBuffer) :
        m_immutableParameters{immutableParameters},
        m_mutableDataBuffer{mutableDataBuffer}
    {
    }

    void processBuffer();
private:
    const Params& m_immutableParameters;
    const DataBuffer& m_mutableDataBuffer;
};

这里的语义差异仅在名称中给出.

问题是const&实例变量只让您知道该实例不会修改该对象.界面中没有区别是否可以在其他地方修改它们,我认为这是一个有用的功能,能够在界面中进行描述.

通过类型系统表达这一点将有助于使接口更清晰,允许编译器捕获错误(例如C,在上面的示例中意外修改传递给实例的参数,在实例之外),并且可能有助于编译器优化.

假设答案是在C++中无法区分,可能有些东西可以通过一些模板魔术来实现吗?



1> Nicol Bolas..:

不可变性不是 C++类型系统的一部分.因此,您无法区分不可变对象和可变对象.即使你能,std::as_const永远毁了你试图这样做.

如果您正在编写一个需要对象不变的接口,最简单的方法就是调用软件工程的基本定理:"我们可以通过引入额外的间接层来解决任何问题." 因此,使不变性成为类型系统的一部分.例如(仅供参考:使用一些小型C++ 17库):

template
class immutable
{
public:
  template
  immutable(std::in_place_t, Args &&...args) t(std::forward(args)...) {}

  immutable() = default;
  ~immutable() = default;

  immutable(const immutable &) = default;
  //Not moveable.
  immutable(immutable &&) = delete;

  //Not assignable.
  immutable operator=(const immutable &) = delete;
  immutable operator=(immutable &&) = delete;

  const T* operator->() const {return &t;}
  const T& operator*() const {return t;}

private:
  const T t;
};

使用这种类型,无论用户如何声明它们,内部T都是不可变的.你的类现在应该采取的.并且由于无法通过现有的复制或移动来构造,因此用户无论何时想要将其作为参数传递都被强制使用.immutableCimmutableconst&immutableTimmutable

当然,你最大的危险是他们会暂时过关.但那是你已经需要解决的问题.


@dave AFAIK这是完全错误的.如果你存储一个普通的const引用,那么当你访问它时(例如每次在新的方法调用中第一次访问它时)编译器必须假设一些其他无关的代码,这些代码具有对象的非const引用可能有更改了对象,因此必须取消引用该对象.
@Danra:那会延伸多远?毕竟,你必须使用`*`或` - >`来获取对象,最终导致引用(或`this`指针).`T`的每个`const`成员函数都可以假定它将在不可变对象上调用吗?在经过大量内联之后,编译器可能能够将指针或引用追溯到`immutable`.但除非它内联你使用`T`的函数,否则它不会*知道`T`是不可变的.

2> Rakete1111..:

我不知道原因,但是你可以这样做:

struct C {
   template
   C(T&&, const T2&&) = delete;

   C(const Params&, const DataBuffer&) { /*...*/ }
};

通过声明一个由非const引用接受任何参数的构造函数,它总是比构造函数更好地匹配const&,因为不必添加cv-qualifier.

const&构造函数是一个更好的匹配传递时const的参数,作为CV-预选赛并没有被删除.

DataBuffer db;

const Params cp;
C c{ cp, db }; // ok, second constructor call is chosen

Params p;
C c2{ p, db }; // error, constructor is deleted

请注意,正如@IgorTandetnik 所说,您可以轻松地打破您的要求:

Params pa;
const Params& ref_pa = pa;
C c3{ ref_pa, db }; // ok, but shouldn't compile.


可能仍然被"DataBuffer db"之类的东西所欺骗; const DataBuffer&dbRef = db; C c(...,dbRef);`.也许不太可能故意发生,但是一个本身需要const ref的函数可以将它传递给`C`.
推荐阅读
乐韵答题
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有