是否可以为 void* 创建 shared_ptr?
is it possible to create shared_ptr for void*?
我有 class 可以包含指向某些数据和他的数据类型的指针。
所以在每时每刻我都可以使用转换为正确类型来处理这些数据。
这里是 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
重写它。但我的主要问题 data
是 void*
。有什么技巧可以帮到我吗?
更新:
写这个 class 的主要目的是在一个队列中存储一些不同的数据
喜欢 queue<MyClass>
未知数太多,无法单方面回答。
- 如果你知道编译前的类型,你可以将这个class转换成一个模板。
- 如果你想要类型安全,你可以使用类型安全联合 -
std::variant
- 您可以创建一个工厂或访问者 class 来为每个存储class分配和分离 classes
- 如果您需要将数据存储在整体数组中,例如使用一些外部的、非 C++ API,例如OpenGL,你必须切换到
unsigned char*
Is there is some techniques that may helps me?
你当然可以做到。这是您的 class 的更新版本,其中包含一些测试代码。
#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*
我无法说明使用 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);
当最后一个引用消失时,将调用最初实例化项的正确析构函数。通过 class 实例亲自查看。
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 边界的。如果 shared_ptr 实例在 DLL 或共享库单元之间传递,原始类型(和正确的析构函数)可能会丢失。
您可以提供删除器:(默认的是正确的,因此可以使用 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;
};
我有 class 可以包含指向某些数据和他的数据类型的指针。 所以在每时每刻我都可以使用转换为正确类型来处理这些数据。
这里是 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
重写它。但我的主要问题 data
是 void*
。有什么技巧可以帮到我吗?
更新:
写这个 class 的主要目的是在一个队列中存储一些不同的数据
喜欢 queue<MyClass>
未知数太多,无法单方面回答。
- 如果你知道编译前的类型,你可以将这个class转换成一个模板。
- 如果你想要类型安全,你可以使用类型安全联合 -
std::variant
- 您可以创建一个工厂或访问者 class 来为每个存储class分配和分离 classes
- 如果您需要将数据存储在整体数组中,例如使用一些外部的、非 C++ API,例如OpenGL,你必须切换到
unsigned char*
Is there is some techniques that may helps me?
你当然可以做到。这是您的 class 的更新版本,其中包含一些测试代码。
#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*
我无法说明使用 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);
当最后一个引用消失时,将调用最初实例化项的正确析构函数。通过 class 实例亲自查看。
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 边界的。如果 shared_ptr 实例在 DLL 或共享库单元之间传递,原始类型(和正确的析构函数)可能会丢失。
您可以提供删除器:(默认的是正确的,因此可以使用 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;
};