【问题标题】:Is it possible to turn an already initialized variable into a void*?是否可以将已经初始化的变量变成 void*?
【发布时间】:2020-09-10 15:41:08
【问题描述】:

这是一个语言限制的问题,请不要回答“你不应该这样做”,你是否应该不重要,重要的是你能不能 /em>。

假设我们要编写一个获取任何对象所有权的子程序,我们可以这样写,例如:

void function(void* object)
{
   // store the pointer somewhere
}

auto ptr = new MyObject(params);
function(ptr);

上述方法有效,但强制用户使用new 运算符初始化他想要存储的对象。我想知道你是否可以“窃取”对象的内容,即使它是正常初始化的。

我想知道你是否可以做类似的事情:

template <typename T>
void function(T& object)
{
   void* ptr = malloc(sizeof(T));
   *ptr = std::move(object); // Or somehting like this
   // store ptr somewhere
}

MyObject object(params);
function(object);
// object variable is now invalid

【问题讨论】:

  • 您可能正在寻找new(ptr) T(std::move(object)); 另请参阅:en.cppreference.com/w/cpp/language/new#Placement_new
  • 您需要解决的实际问题是什么?为什么你需要做这样的事情?如果您想要所有权语义,为什么不使用其中一个智能指针(如std::unique_ptr)开始呢?
  • Placement new 将允许您在已分配的内存中创建一个对象。但在这里你也可以直接说void *ptr = new T(std:::move(object)); 当然,真正的诀窍是让 T 安全退出。
  • @rustyx std:: any can't store moveable only types
  • @Mat 不能;只做可移动类型

标签: c++ pointers memory void-pointers


【解决方案1】:

假设我们要编写一个获取任何对象所有权的子例程。

这当然不能单独使用void指针,因为所有权意味着负责删除动态对象,不可能通过void指针删除对象。

这可以通过使用删除函数对象来实现。没有必要为此编写包装类,因为标准库已经涵盖了您1

我想知道你是否可以做类似的事情:

void* ptr = malloc(sizeof(T));
*ptr = std::move(object);

不完全是这样,因为你不能通过指向 void 的指针间接,而且你还没有在那里创建一个对象,所以没有什么可以分配的。

从左值引用参数转移也是一个坏主意。

您似乎试图做的是创建一个动态对象,该对象是参数对象的副本(通过移动)。以下是如何做到这一点的示例:

template <typename T>
void function(T&& object)
{
    auto ptr = std::make_unique<T>(std::move(object));

你可以像这样得到一个指向 void 的指针:

void* void_ptr = ptr.get();

1 对任何类型的对象进行类型擦除(可以通过指向 void 的指针来实现),但也能够拥有该对象(与指向 void 的指针不同),有一个类型对于标准库中的那个:std::any.

【讨论】:

  • "并且无法通过 void 指针删除对象。"免费(无效*);如果需要自定义取消分配,请请求一个附加参数,该参数是删除对象的函数。
  • @Makogan 您希望能够拥有 any 对象的所有权。对于任何非平凡可破坏的类型,std::free 是不够的。
  • std::any 不能包含只能移动的类型
  • 你是对的,这就是为什么我为那些免费的情况描述了一种机制。因为有些时候是 100% 正确的;free 不能正确处理
  • @Makogan 这也是我在回答中所说的:除了指向 void 的指针之外,您还需要一个销毁函数。当然,您可以针对不需要它的特殊情况对其进行优化。虽然没有必要使用mallocfree
【解决方案2】:

您当然可以从非动态分配的事物中移出,也可以移至 动态分配的事物中。

这仅在“移动”对您的类型有意义且有价值的情况下才有用。否则,您将无法复制数据。

请记住:std::move 实际上并没有在转移或改变其生命周期的意义上移动对象;它只是允许编译器选择构造函数和赋值运算符重载,可能执行一些间接状态的廉价传输,以避免深度复制的成本。

【讨论】:

    猜你喜欢
    • 2011-10-12
    • 1970-01-01
    • 1970-01-01
    • 2018-02-20
    • 2011-01-26
    • 1970-01-01
    • 2016-10-03
    • 2015-10-24
    • 2014-07-26
    相关资源
    最近更新 更多