Propagate constness to data pointed by member variables

前端 未结 4 1627
难免孤独
难免孤独 2020-12-14 16:41

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 refer

相关标签:
4条回答
  • 2020-12-14 17:02

    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();
        }
    };
    
    0 讨论(0)
  • 2020-12-14 17:16
    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&> {};
    
    0 讨论(0)
  • 2020-12-14 17:16

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

    0 讨论(0)
  • 2020-12-14 17:16

    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.

    0 讨论(0)
提交回复
热议问题