为什么uninitialized_copy中需要voidify函数模板

Kal*_*Kal 8 c++ templates function-templates

我正在阅读std::uninitialized_copy并发现了一个叫做voidify

效果: 相当于:

for (; first != last; ++result, (void) ++first)
//#1----vvvvvvv----------->what does this call to voidify mean here
 ::new (voidify(*result))
   typename iterator_traits<NoThrowForwardIterator>::value_type(*first);
Run Code Online (Sandbox Code Playgroud)

经过进一步查找voidify,我发现它是一个函数模板:

本节中指定的一些算法使用仅说明函数 voidify:

template<class T>
 constexpr void* voidify(T& obj) noexcept {
//#2------vvvvvvvvvv-------------------------------->why does this const_cast to void* is needed
   return const_cast<void*>(static_cast<const volatile void*>(addressof(obj)));
//#3------------------------^^^^^^^^^^^------------->why this static_cast to const volatile void* is needed
 }
Run Code Online (Sandbox Code Playgroud)

正如我们所看到的,它voidify返回了void*toobj或其他我不太明白的东西,因为涉及到一些强制转换,我不知道为什么需要它们。我已发表评论表明我的疑问。有人可以逐步告诉我为什么voidify需要new (voidify(*result))以及为什么const_cast需要static_cast

总之(只是为了清楚地表达我的疑问)我的问题是:

  1. 为什么我们需要打电话voidify进来new (voidify(*result))。我知道这是使用 palcement-new,但我不知道作为参数调用voidify和传递,然后使用placement-new 的返回值的原因。*result

  2. 为什么const_cast这里用的是. reinterpret_cast为什么不是像or 之类的其他演员呢static_cast?这就是这里需要选择的const_cast

  3. 为什么static_cast这里使用的是而不是其他一些演员。

  4. 为什么我们不能只写return addressof(obj);or return (void*)(addressof(obj);.

请注意,我试图了解该equivalent to版本的工作原理。我在不同部分提出问题的原因是因为我认为将其分为单独的步骤,然后理解这些单独的步骤可以让我们更好地理解一个主题。归根结底,我想知道它是如何工作的equivalent version

use*_*445 3

为什么我们需要在new(voidify(*result))中调用voidify。我知道这是使用 palcement-new 但我不知道我们是否调用 voidify 并将 *result 作为参数传递,然后使用 Placement-new 的返回值。

首先要指出的是,在很多情况下,代码可以在没有 的情况下工作voidify,因此,如果您的直觉认为它可以在没有 voidify 的情况下工作,这就是原因。是voidify为了防止存在多个重载版本的情况operator new,并且会选择其中一个而不是放置 newoperator new(size_t, void*);

为什么这里使用const_cast。为什么不使用其他类型的转换,例如reinterpret_cast 或static_cast。这就是这里选择const_cast的需要。

为什么这里使用 static_cast 而不是其他一些强制转换。

如果你想草率一点,你也可以只用一个 C 风格的强制转换来做到这一点,如下所示:

return (void*) addressof(obj);
Run Code Online (Sandbox Code Playgroud)

但每个const_cast和 的static_cast作用都不同,您可能需要其中一种或两种类型的转换。您可以替换static_castreinterpret_cast,但它不会给您带来任何好处,并且可能会使捕获某些错误变得更加困难,因此此时您最好使用 C 风格的强制转换。

为什么我们不能只写 return addressof(obj); 或返回 (void*)(addressof(obj);。

如果您碰巧有一个超载的 . 则前者会意外失败operator new(std::size_t, decltype(addressof(obj))。正如前面提到的,后者(C 风格的演员阵容)非常好。