将常数传递给成员变量指向的数据 [英] Propagate constness to data pointed by member variables

查看:143
本文介绍了将常数传递给成员变量指向的数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于C ++新手来说,const成员函数允许在类引用的对象上调用非const方法(通过指针或引用),这通常是很混乱的。例如,以下是完全正确的:

It is often quite confusing to C++ newcomers that const member functions are allowed to call non-const methods on objects referenced by the class (either by pointer or reference). For example, the following is perfectly correct:

class SomeClass
{
    class SomeClassImpl;
    SomeClassImpl * impl_; // PImpl idiom

  public:    

    void const_method() const;
};

struct SomeClass::SomeClassImpl
{
    void non_const_method() { /*modify data*/ }
};

void SomeClass::const_method() const
{
    impl_->non_const_method(); //ok because impl_ is const, not *impl_
};

但是,如果const会传播到尖锐的对象PImpl成语,因为它是我认为constness propagation非常有用的情况之一)。

However, it would sometimes be rather handy if the constness would propagate to pointed objects (I voluntarily used the PImpl idiom because it is one of the case where I think "constness propagation" would be very useful).

当使用指针时,这可以很容易地通过使用某种智能指针,其中运算符对const const重载:

When using pointers, this can easily be achieved by using some kind of smart pointer with operators overloaded on constness:

template < typename T >
class const_propagating_ptr
{
  public:

    const_propagating_ptr( T * ptr ) : ptr_( ptr ) {}

    T       & operator*()       { return *ptr_; }
    T const & operator*() const { return *ptr_; }

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

    // assignment operator (?), get() method (?), reset() method (?)
    // ...

  private:

    T * ptr_;
};

现在,我只需要修改 SomeClass :: impl _ const_propagating_ptr< SomeClassImpl> 以获得想要的行为。

Now, I just need to modify SomeClass::impl_ to be a const_propagating_ptr<SomeClassImpl> to obtain the wanted behavior.

关于此:


  1. 我忽略了常量传播的一些问题?

  2. ,是否有任何库提供类来获取常量传播?

  3. 常见的智能指针(unique_ptr,shared_ptr等)提供某种意义, (例如通过模板参数)?


推荐答案


  1. p> As @Alf P. Steinbach指出,你监督的事实是,复制你的指针会产生一个非const对象指向同一个底层对象。 Pimpl (下面)通过执行深层副本, unique_ptr 通过不可复制来避开问题。
  1. As @Alf P. Steinbach noted, you oversaw the fact that copying your pointer would yield a non-const object pointing to the same underlying object. Pimpl (below) nicely circumvent the issue by performing a deep-copy, unique_ptr circumvents it by being non-copyable. It is much easier, of course, if the pointee is owned by a single entity.

Boost.Optional 传播常量,但它不完全是一个指针(虽然它模型OptionalPointee概念)。我知道没有这样的其他图书馆。

Boost.Optional propagates const-ness, however it's not exactly a pointer (though it models the OptionalPointee concept). I know of no such other library.

我希望他们默认提供。添加另一个模板参数(traits类我猜)似乎不值得的麻烦。但是,这将从根本上改变一个经典指针的语法,所以我不确定人们会准备好接受它。

I would favor that they provide it by default. Adding another template parameter (traits class I guess) does not seem worth the trouble. However that would radically change the syntax from a classic pointer, so I am not sure that people would be ready to embrace it.






Pimpl 类的代码

template <class T>
class Pimpl
{
public:
  /**
   * Types
   */
  typedef T value;
  typedef const T const_value;
  typedef T* pointer;
  typedef const T* const_pointer;
  typedef T& reference;
  typedef const T& const_reference;

  /**
   * Gang of Four
   */
  Pimpl() : _value(new T()) {}
  explicit Pimpl(const_reference v) : _value(new T(v)) {}

  Pimpl(const Pimpl& rhs) : _value(new T(*(rhs._value))) {}

  Pimpl& operator=(const Pimpl& rhs)
  {
    Pimpl tmp(rhs);
    swap(tmp);
    return *this;
  } // operator=

  ~Pimpl() { boost::checked_delete(_value); }

  void swap(Pimpl& rhs)
  {
    pointer temp(rhs._value);
    rhs._value = _value;
    _value = temp;
  } // swap

  /**
   * Data access
   */
  pointer get() { return _value; }
  const_pointer get() const { return _value; }

  reference operator*() { return *_value; }
  const_reference operator*() const { return *_value; }

  pointer operator->() { return _value; }
  const_pointer operator->() const { return _value; }

private:
  pointer _value;
}; // class Pimpl<T>

// Swap
template <class T>
void swap(Pimpl<T>& lhs, Pimpl<T>& rhs) { lhs.swap(rhs); }

// Not to be used with pointers or references
template <class T> class Pimpl<T*> {};
template <class T> class Pimpl<T&> {};

这篇关于将常数传递给成员变量指向的数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆