带有智能指针的 CRTP
CRTP with smart pointers
我正在试验 CRTP 的概念以及如何将其用于近似 C++ 中的混合。
我开发了以下代码来说明这个想法,但是当向量 shapeVec 试图删除智能指针时遇到了一个问题,它会导致分段错误。
有人可以解释一下这种方法有什么问题吗?
谢谢
#include <memory>
#include <vector>
#include <iostream>
using namespace std;
struct Shape
{
virtual unique_ptr<Shape> clone ()= 0;
virtual int getX() = 0;
virtual ~Shape()=default;
};
template <typename T>
struct CloneMixin
{
unique_ptr<Shape> clone ()
{
return unique_ptr<T>(static_cast<T*>(this));
}
};
template <typename T>
struct GetterMixin
{
int getX()
{
return static_cast<T*>(this)->x;
}
};
struct Square : public CloneMixin<Square>, public GetterMixin<Square>, public Shape
{
int x=1;
virtual unique_ptr<Shape> clone() override { return CloneMixin::clone();}
virtual int getX() override { return GetterMixin::getX();}
virtual ~Square()=default;
};
struct Rectangle : public CloneMixin<Rectangle>, public GetterMixin<Rectangle>, public Shape
{
int x=2;
int y=3;
virtual unique_ptr<Shape> clone() override { return CloneMixin::clone();}
virtual int getX() override { return GetterMixin::getX();}
virtual ~Rectangle()=default;
};
int main()
{
vector < unique_ptr<Shape>> shapeVec;
shapeVec.push_back(make_unique< Square>());
shapeVec.push_back(make_unique<Rectangle>());
for (auto &i : shapeVec)
{
unique_ptr<Shape> ss = i->clone();
cout << ss->getX()<<endl;
}
return 0;
}
编辑:我的克隆函数有误。它返回 shapeVec 中对象的相同指针。此类对象在主函数中删除(ss)唯一指针时被删除了一次。当 shapeVec 试图删除它自己的指针时,它们之前已经删除了。这导致了异常。
我将 CloneMixin 中的克隆函数更改为以下内容,它按预期工作:
unique_ptr<T> clone ()
{
return make_unique<T>(*static_cast<T*>(this));
}
问题在于您实际上并未在 CloneMixin::clone
中进行克隆。您正在返回一个新的 unique_ptr,它管理与您应该克隆的对象相同的对象。这显然是一个错误。解决办法就是实际复制一份。
假设每个形状都有一个复制构造函数,那么您可以做类似的事情
template <typename T>
struct CloneMixin
{
unique_ptr<Shape> clone()
{
T* this_shape = static_cast<T*>(this);
return unique_ptr<T>( new T(*this_shape) );
}
};
你也可以在那里使用 make_unique<T>
,成员函数可以是 const
,给定合适的 const ref 复制构造函数。
我正在试验 CRTP 的概念以及如何将其用于近似 C++ 中的混合。
我开发了以下代码来说明这个想法,但是当向量 shapeVec 试图删除智能指针时遇到了一个问题,它会导致分段错误。
有人可以解释一下这种方法有什么问题吗? 谢谢
#include <memory>
#include <vector>
#include <iostream>
using namespace std;
struct Shape
{
virtual unique_ptr<Shape> clone ()= 0;
virtual int getX() = 0;
virtual ~Shape()=default;
};
template <typename T>
struct CloneMixin
{
unique_ptr<Shape> clone ()
{
return unique_ptr<T>(static_cast<T*>(this));
}
};
template <typename T>
struct GetterMixin
{
int getX()
{
return static_cast<T*>(this)->x;
}
};
struct Square : public CloneMixin<Square>, public GetterMixin<Square>, public Shape
{
int x=1;
virtual unique_ptr<Shape> clone() override { return CloneMixin::clone();}
virtual int getX() override { return GetterMixin::getX();}
virtual ~Square()=default;
};
struct Rectangle : public CloneMixin<Rectangle>, public GetterMixin<Rectangle>, public Shape
{
int x=2;
int y=3;
virtual unique_ptr<Shape> clone() override { return CloneMixin::clone();}
virtual int getX() override { return GetterMixin::getX();}
virtual ~Rectangle()=default;
};
int main()
{
vector < unique_ptr<Shape>> shapeVec;
shapeVec.push_back(make_unique< Square>());
shapeVec.push_back(make_unique<Rectangle>());
for (auto &i : shapeVec)
{
unique_ptr<Shape> ss = i->clone();
cout << ss->getX()<<endl;
}
return 0;
}
编辑:我的克隆函数有误。它返回 shapeVec 中对象的相同指针。此类对象在主函数中删除(ss)唯一指针时被删除了一次。当 shapeVec 试图删除它自己的指针时,它们之前已经删除了。这导致了异常。
我将 CloneMixin 中的克隆函数更改为以下内容,它按预期工作:
unique_ptr<T> clone ()
{
return make_unique<T>(*static_cast<T*>(this));
}
问题在于您实际上并未在 CloneMixin::clone
中进行克隆。您正在返回一个新的 unique_ptr,它管理与您应该克隆的对象相同的对象。这显然是一个错误。解决办法就是实际复制一份。
假设每个形状都有一个复制构造函数,那么您可以做类似的事情
template <typename T>
struct CloneMixin
{
unique_ptr<Shape> clone()
{
T* this_shape = static_cast<T*>(this);
return unique_ptr<T>( new T(*this_shape) );
}
};
你也可以在那里使用 make_unique<T>
,成员函数可以是 const
,给定合适的 const ref 复制构造函数。