【问题标题】:Trying to 'replicate' shared_ptr upcasting behaviour cause an infinite recursion on copy constructor (that lead to a segfault)尝试“复制”shared_ptr 向上转换行为会导致复制构造函数的无限递归(导致段错误)
【发布时间】:2019-06-05 08:33:54
【问题描述】:

我正在尝试复制 shared_ptr 行为以更好地理解 c++17 中的模板元编程和 type_traits。 具体来说,我想复制向上转换的行为,即在没有任何显式转换的情况下将 shared_ptr< Derived > 分配/复制创建到 shared_ptr< Base > 的机会。

类型检查正常,但是当我尝试复制或分配派生对象时,我在复制构造函数中遇到了无限循环的段错误。

通用模板类

#pragma once

#include <memory>
#include <type_traits>

template <typename T>
class Generic {
    public:
        template <typename DerivedT>
        using Assignable = typename std::enable_if<std::is_assignable<T, DerivedT>::value, Generic<T> &>::type;

        Generic() : _ptr(nullptr) {}


        Generic(T *ptr) : _ptr{ptr} {};

        Generic(Generic && cptr) :
                _ptr(std::move(cptr._ptr))
        {}

        Generic(const Generic & cptr) :
                _ptr{cptr._ptr}
        {}

        template <typename DerivedT, typename = Assignable<DerivedT>>
        Generic(const Generic<DerivedT> &cptr) 
            : Generic(static_cast<const Generic &>(cptr)._ptr)
        {}

        ~Generic() = default;

        Generic & operator=(Generic && cptr) = default;

        Generic & operator=(const Generic & cptr) {
            _ptr = cptr._ptr;
            return *this;
        }

        template <typename DerivedT>
        Assignable<DerivedT> operator=(const Generic<DerivedT> &cptr) {
            _ptr = static_cast<const Generic &>(cptr)._ptr;
            return *this;
        }

    private:
        T* _ptr;
};

main.cpp

#include "Generic.hpp"

struct Base {
};

struct Derived : public Base {
};

int main() {
    Generic<Derived> derived = Generic<Derived>();
    Generic<Base> base(derived);
    //Generic<Base> base = derived;
}

【问题讨论】:

    标签: c++ templates c++17 template-meta-programming


    【解决方案1】:

    您的问题可以简化为:

    template <typename T>
    class Generic {
        public:
            Generic() = default;
    
            Generic(T *ptr) : _ptr{ptr} {};
    
            template <typename Derived>
            Generic(const Generic<Derived> &cptr) :
              Generic(static_cast<const Generic &>(cptr)._ptr)
            {}
    
        private:
            T* _ptr = nullptr;
    };
    
    struct Base {
    };
    
    struct Derived : public Base {
    };
    
    int main() {
        Generic<Derived> derived = Generic<Derived>();
        Generic<Base> base(derived);
    }
    

    问题在于,使用static_cast&lt;const Generic &amp;&gt;(cptr),您隐式创建了Generic&lt;T&gt; 形式Generic&lt;Derived&gt; 的实例,因此递归调用构造函数无限

    一个可能的解决办法是:

    template <typename T>
    class Generic {
        public:
            Generic() = default;
    
            Generic(T *ptr) : _ptr{ptr} {};
    
            template <typename Derived>
            Generic(const Generic<Derived> &cptr) :
              Generic(cptr._ptr)
            {}
    
        private:
            T* _ptr = nullptr;
    
        template <typename U>
        friend class Generic;
    };
    
    struct Base {
    };
    
    struct Derived : public Base {
    };
    
    int main() {
        Generic<Derived> derived = Generic<Derived>();
        Generic<Base> base(derived);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多