【问题标题】:CRTP with smart pointers带有智能指针的 CRTP
【发布时间】:2021-01-02 14:57:44
【问题描述】:

我正在试验 CRTP 的概念以及如何使用它来近似 C++ 中的 mixin。

我已经开发了以下代码来说明这个想法,但是当向量 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));
    }

【问题讨论】:

  • 可以添加错误堆栈吗?
  • 你希望你的clone 函数能做什么?
  • 用地址清理器clang.llvm.org/docs/AddressSanitizer.html编译和链接,然后再次运行代码
  • @t.niese 谢谢你的评论,伙计。你让我真的又想起了克隆功能,问题确实在那里。现在编辑后,它工作正常。
  • clone() 甚至可以是const

标签: c++ smart-pointers crtp


【解决方案1】:

问题是您实际上并没有在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&lt;T&gt;,并且成员函数可以是const,给定合适的 const ref 复制构造函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-23
    • 2014-03-23
    • 1970-01-01
    • 2021-03-29
    • 2021-12-26
    • 2020-03-01
    • 2020-10-08
    • 2021-08-24
    相关资源
    最近更新 更多