是否可以为void *创建shared_ptr?

时间:2018-08-14 06:13:37

标签: c++ shared-ptr

我有一个可以包含指向某些数据及其数据类型的指针的类。 因此,每时每刻我都可以使用强制类型正确的数据来处理这些数据。

以下是int和float的示例:

enum MyType {
    NO_TYPE,
    INT,
    FLO
};

class MyClass {
public:
    MyType type;
    void* data;

    MyClass(int i)
        :
            type(MyType::INT)
    {
        data = (void*) new int(i);
    }

    MyClass(float i)
        :
            type(MyType::FLO)
    {
        std::cout << "Constructor\n";
        data = (void*) new float(i);
    }

    MyClass()
        :
            type(MyType::NO_TYPE)
    {
        std::cout << "Constructor (default)\n";
        data = nullptr;
    }

    void Copy(const MyClass &from)
    {
        this->type = from.type;
        if (this->type == MyType::INT)
            this->data = (void*) new int (*((int*)from.data));
        if (this->type == MyType::FLO)
            this->data = (void*) new float (*((float*)from.data));
    }

    MyClass(MyClass &from) {
        std::cout << "Copy constructor\n";
        Copy((const MyClass&)from);
    }

    MyClass(const MyClass &from) {
        std::cout << "Copy constructor\n";
        Copy(from);
    }

    ~MyClass() {
        std::cout << "Destructor for type "  << this->type << "\n";
        if (this->type == MyType::INT)
            delete (int*)this->data;
        if (this->type == MyType::FLO)
            delete (float*)this->data;
        this->data = nullptr;
    }
};

我想用shared_ptr重写它。但是我的主要问题是datavoid*。有一些技巧可以帮助我吗?

更新: 编写此类的主要目的是将一些不同的数据存储在一个队列中 像queue<MyClass>

4 个答案:

答案 0 :(得分:4)

我无法说出使用shared_ptr<void>的价值,但是它可以用作指针的通用容器。

这些有效:

int i = 42;
std::shared_ptr<void> spVoid = std::make_shared<int>(i);

float f = 3.14f;
std::shared_ptr<void> spVoid = std::make_shared<float>(f);

当最后一个引用消失时,将调用原始实例化项目的正确析构函数。通过类实例亲自查看。

struct Foo
{
    Foo()
    {
        std::cout << "Foo constructor" << std::endl;
    }

    ~Foo()
    {
        std::cout << "Foo destructor" << std::endl;
    }
};

int main()
{
    std::shared_ptr<void> spVoid = std::make_shared<Foo>();
    return 0;
}

关于向上传播shared_ptr的唯一警告是关于跨越DLL边界。如果在DLL或共享库单元之间传递了shared_ptr实例,则原始类型(和正确的析构函数)可能会丢失。

答案 1 :(得分:0)

有太多未知数无法单方面回答。

  • 如果在编译之前知道类型,则可以将此类转换为模板。
  • 如果需要类型安全,则可以使用类型安全的联合-std::variant
  • 您可以创建一个工厂或访客类,为每个存储进行分配和单独的类
  • 如果您需要将数据存储在单片数组中,例如使用某些外部非C ++ API,例如OpenGL,您必须切换到unsigned char*

答案 2 :(得分:0)

  

有一些技巧可以帮助我吗?

您当然可以做到。这是您班级的更新版本,其中包含一些测试代码。

#include <iostream>
#include <memory>

enum MyType {
   NO_TYPE,
   INT,
   FLO
};

class MyClass {
   public:
      MyType type;
      std::shared_ptr<void> data;

      static void int_deleter(int* ptr)
      {
         std::cout << "Deleting an int*\n";
         delete ptr; 
      }

      static void float_deleter(float* ptr)
      {
         std::cout << "Deleting a float*\n";
         delete ptr;
      }

      MyClass(int i) : type(MyType::INT), data(new int(i), int_deleter)
      {
         std::cout << "Constructor with int\n";
      }

      MyClass(float i) : type(MyType::FLO), data(new float(i), float_deleter)
      {
         std::cout << "Constructor with float\n";
      }

      MyClass() : type(MyType::NO_TYPE)
      {
         std::cout << "Constructor (default)\n";
      }

      // Can be a private member function.
      static std::shared_ptr<void> make_data(const MyClass &from)
      {
         switch ( from.type )
         {
            case MyType::INT:
               return std::shared_ptr<void>(new int (*((int*)from.data.get())), int_deleter);

            case MyType::FLO:
               return std::shared_ptr<void>(new float (*((float*)from.data.get())), float_deleter);

            default:
               return {};
         }

         return {};
      }

      MyClass(MyClass &from) : type(from.type), data(make_data(from))
      {
         std::cout << "Copy constructor\n";
      }

      MyClass(const MyClass &from) : type(from.type), data(make_data(from))
      {
         std::cout << "Copy constructor\n";
      }

      ~MyClass()
      {
         std::cout << "Destructor for type "  << this->type << "\n";
      }
};

void test_int()
{
   MyClass c1(10);
   MyClass c2(c1);
}

void test_float()
{
   MyClass c1(10.2f);
   MyClass c2(c1);
}

int main()
{
   test_int();
   test_float();
}

输出:

Constructor with int
Copy constructor
Destructor for type 1
Deleting an int*
Destructor for type 1
Deleting an int*
Constructor with float
Copy constructor
Destructor for type 2
Deleting a float*
Destructor for type 2
Deleting a float*

答案 3 :(得分:0)

您可以提供Deleter :(默认情况下是正确的,因此可以使用std::make_shared)。

class MyClass {
public:
    MyType type = MyType::NO_TYPE;
    std::shared_ptr<void> data;

    MyClass() = default;

    MyClass(int i) { set(i); }
    MyClass(float f) { set(f); }

    void Copy(const MyClass &from)
    {
        switch (from.type) {
            case MyType::INT: set(*((int*)from.data.get());
            case MyType::FLO: set(*((float*)from.data.get());
            case MyType::NO_TYPE: set();
        }
    }

    MyClass(const MyClass &from) {
        std::cout << "Copy constructor\n";
        Copy(from);
    }

    void set()
    {
        type = MyType::NO_TYPE;
        data = nullptr;
    }

    void set(int i)
    {
        type = MyType::INT;
        data = std::make_shared<int>(i);
    }

    void set(float f)
    {
        type = MyType::FLO;
        data = std::make_shared<float>(f);
    }

    ~MyClass() = default;
};