是否可以为 void* 创建shared_ptr?

is it possible to create shared_ptr for void*?

本文关键字:shared ptr 创建 void 是否      更新时间:2023-10-16

我有类可以包含指向某些数据的指针和他的数据类型。 因此,在每时每刻,我都可以使用转换为正确类型的数据来操作此数据。

以下是 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 << "Constructorn";
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 constructorn";
Copy((const MyClass&)from);
}
MyClass(const MyClass &from) {
std::cout << "Copy constructorn";
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>

我不能说使用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则原始类型(和正确的析构函数(可能会丢失。

有太多的未知数无法单方面回答这个问题。

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

你可以提供删除器:(默认的是正确的,所以可以使用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 constructorn";
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;
};

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

你当然可以这样做。下面是包含一些测试代码的类的更新版本。

#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 intn";
}
MyClass(float i) : type(MyType::FLO), data(new float(i), float_deleter)
{
std::cout << "Constructor with floatn";
}
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 constructorn";
}
MyClass(const MyClass &from) : type(from.type), data(make_data(from))
{
std::cout << "Copy constructorn";
}
~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*