以下是我一直在尝试调查的用例的简单版本
#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()
函数为我的null
成员变量中的基础整数返回std::unique_ptr
值。
答案 0 :(得分:3)
构建t1
时,使用以下代码构建其m_throw
m_throw ([this]() {
throw intexception("Integer Exception",static_cast<T>(this->get()));
})
也就是说,t1.m_throw
持有t1
(通过指针)。它正在抛出intexception
构建的t1.m_holder.get()
。
当您将其移至t2
时,std::function
中的实际基础lambda不会发生变化。它仍然试图抛出t1.m_holder.get()
。问题是,一旦您从t1.m_holder
移出,解除引用基础unique_ptr
无效 - 这是您的细分错误的来源。
你必须重新绑定投掷者,以确保你总是从this
投掷。最简单的方法是将TypedInt
实例作为参数传递,然后您不必担心任何事情。
答案 1 :(得分:2)
您可以在lambda中捕获this
的值。在所有移动之后,您捕获的this
指针不再指向有效对象。
this
捕获不会“跟踪”捕获的对象。
您可以尝试简单地使用实现来捕获intid
。
m_throw ( [intid]() {
throw intexception("Integer Exception", static_cast<int>(intid));
} )
否则;如果lambda需要使用当前对象,则在调用lambda时,this
指针可以作为参数传入。在这种情况下,鉴于用例,lambda似乎“很重”。
最好避免使用lambda,并在需要时简单地throw
;使用throw
时对象中的值。