Propagate constness to data pointed by member variables

浪子不回头ぞ 提交于 2019-11-28 21:15:48
  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.

  2. 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.

  3. 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.


Code of the Pimpl class

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&> {};

One approach is to just not use the pointer directly except through two accessor functions.

class SomeClass
{
  private:
    class SomeClassImpl;
    SomeClassImpl * impl_; // PImpl idiom - don't use me directly!

    SomeClassImpl * mutable_impl() { return impl_; }
    const SomeClassImpl * impl() const { return impl_; }

  public:    

    void const_method() const
    {
      //Can't use mutable_impl here.
      impl()->const_method();
    }
    void non_const_method() const
    {
      //Here I can use mutable_impl
      mutable_impl()->non_const_method();
    }
};
Luc Touraille

For the record, I just found out that the Loki library does provide a const propagating pointer (ConstPropPtr<T>). It looks just like the one in the question, except that it also deletes the wrapped pointer in its destructor, and it is used to implement a Pimpl class similar to the one proposed by @Matthieu (but not copyable).

curiousguy

If you think it should "propagate" const-ness, then it means you don't really believe it is a pointer (or reference), but you believe it is a container: if the value is constant when the object is constant, it's because the object contains the value.

So copying the object copies the value, at least logically (CoW).

If you insist that it is a pointer/reference IOW that you can copy the object while sharing the contained value, then you have an unsound (contradicting) interface.

Conclusion: make up your mind. It is either a container or a pointer.

A pointer does not propagate const-ness, by definition.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!