c++ - 使用 lambdas 将模板类型的成员作为异常抛出

标签 c++ c++11 lambda

这是我一直在尝试调查的用例的简单版本

#include<iostream>
#include<stdexcept>
#include<memory>
#include<type_traits>
#include<string>

class intexception:public std::exception
{
    public:

        intexception(std::string m,int x):msg(m),g(x){}

        const char* what() const throw() { return msg.c_str(); }
        virtual ~intexception() throw(){}
        int getExceptInt()const { return g;}

    private:
        std::string msg;
        int g;
};

class Int
{ 
    public: 
        Int():m_ptr(nullptr){}
        Int(const int& x) : m_ptr(new int(x)) { }

        Int(const Int& in) : m_ptr( (in.get()) ? ( new int(*in.m_ptr) ) : ( nullptr ) ) {}
        Int& operator=(const Int&) = default;

        Int(Int&&) = default;
        Int& operator=(Int&&) = default;

        int get() const { return *m_ptr; }         

    private:
        std::unique_ptr<int>m_ptr;
}; 

class TypedInt
{
    public:
    template<typename T, 
        typename std::enable_if< std::is_same<typename std::decay<T>::type,int>::value || std::is_same<typename std::decay<T>::type,long>::value, 
                                 std::nullptr_t>::type = nullptr>

            explicit TypedInt (T& intid )
            : m_holder( intid ),
              m_throw ( [this]() { throw intexception("Integer Exception",static_cast<T>(this->get())); } )
              {}

    TypedInt():m_holder(),m_throw(std::function<void()>()){}

    TypedInt& operator=(TypedInt&&) = default;
    TypedInt(TypedInt&& other):m_holder(std::move(other.m_holder)),m_throw(std::move(other.m_throw)) {}

    TypedInt& operator=(const TypedInt&) = default;
    TypedInt(const TypedInt&) = default;

    int get() const { return m_holder.get(); }

    void Throw() { m_throw(); }

    private:
        Int m_holder;
        std::function<void()>m_throw;
};

void testThrow(TypedInt t)
{
    try
    {
        t.Throw();
    }
    catch(const intexception& e)
    {
        std::cout<<e.what()<<std::endl;
        std::cout<<e.getExceptInt()<<std::endl;
    }
}

int main()
{
    int z = 10;
    TypedInt t1(z);

    TypedInt t2;

    t2 = std::move(t1);

    testThrow(std::move(t2));
    return 0;
}

这可以正常编译,没有问题。但是,它最终会出现段错误。

我看了这个link我觉得我可能面临类似的问题。

我已经用 gdb 对此进行了调试,但我无法理解为什么此 get() 函数会为我的 std 中的基础整数返回一个 null 值: :unique_ptr 成员变量。

最佳答案

当你构造t1时,你构造它的m_throw有:

m_throw ([this]() {
    throw intexception("Integer Exception",static_cast<T>(this->get()));
})

也就是说,t1.m_throw 持有t1(通过指针)。它抛出一个从 t1.m_holder.get() 构造的 intexception

当您将其移动到 t2 时 - std::function 中的实际底层 lambda 不会改变。它仍在尝试抛出 t1.m_holder.get()。问题是,一旦您从 t1.m_holder 移动,取消引用底层 unique_ptr 是无效的 - 这是您的段错误的根源。

您必须重新绑定(bind) throw 器以确保您始终从this throw 。最简单的方法就是将 TypedInt 实例作为参数传入,这样您就不必担心任何事情。

关于c++ - 使用 lambdas 将模板类型的成员作为异常抛出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37117267/

相关文章:

c++ - 编写一个最小的自定义运算符:std::sort 需要为我的类型定义 std::__lg

c++ - 在修改 <some_container> 的大小时迭代 std::vector<some_container> 安全吗?

c++ - std::getline 不适用于函数内部

c++ - 使用回调中的值更新 std::vector 的 GUI slider 的动态数量

c# - 创建类型化的 ModelState.AddModelError()

python - 使用带有两个参数的 lambda 函数映射的 Spark RDD 有什么问题?

c# - 如何在 lambda 表达式中定义为 LINQ Select 方法中的另一个函数

c++ - 如何在 for 循环中进行错误捕获

c++ - 在没有 If/While/For 语句或任何数据结构的情况下计算变化

ios - libc++ for mac os中的可能错误,当字符串obj超出范围时,不调用字符串析构函数