数组和隐式生命周期对象创建

问题描述

一些类型被标准定义为隐式生命周期类型,数组就在其中。 一些函数隐式地创建具有隐式生命周期的对象(malloc 等就在其中), 带有隐式创建具有隐式生命周期的对象的操作列表,可在此处找到。 https://en.cppreference.com/w/cpp/language/object(我希望它是正确的,但对于问题的其余部分,让我们假设 new 在这种情况下用作 malloc 用于隐式对象创建目的)。

如果不创建其元素,隐式创建数组是什么意思?这是否意味着

T* implicit_array = reinterpret_cast<T*>(::operator new(sizeof(T) * count,std::align_val_t{alignof(T)}) );

产生适用于指针运算的implicit_array对象,即为T类型的元素提供有效的存储空间,以便稍后使用placement new构造?
这是否意味着 new (implicit_array + i) T{...}一个定义明确的操作,即使按照标准,implicit_array + i 不一定定义? https://eel.is/c++draft/expr.unary#op-3.2

或者它的意思

std::byte* memory = 
    reinterpret_cast<std::byte*>(::operator new(sizeof(T) * capacity,std::align_val_t{alignof(T)}));
new (memory) T{args1 ...}
// build more objects
new  (memory + (k-1)*sizeof(T) ) T{args_k ...} 
T* implicit_array = std::launder(reinterpret_cast<T*>(memory) ); // does it produce array of k elements?

implicit_array 视为具有 k 个元素的数组?

谢谢。

解决方法

可以先为数组分配存储空间,然后再构造元素。 expr.new/15 中的一个密切相关的注释特别提到“分配字符数组的常见习惯用法”。

发布的代码大多遵循正确的分配-然后构造序列,除了 reinterpret_cast 不安全,实际上没有必要。从分配步骤中返回的 void * 到类型化 T * 的转换是在构造时由放置 new 运算符完成的。

void *alloc_array(size_t cnt)
{
    return ::operator new(sizeof(T) * cnt,std::align_val_t{alignof(T)});
}

T *construct_array(void *buf,size_t cnt)
{
    T *arr = new(buf) T {...},*p = arr;
    for(int i = 1; i < cnt; i++)
        p = new(p + 1) T {...};
    return arr;
}

void destruct_array(T *arr,size_t cnt)
{
    for(int i = cnt; i--; )
        arr[i].~T();
}

void free_array(void *buf,size_t cnt)
{
    ::operator delete(buf,sizeof(T) * cnt,std::align_val_t{alignof(T)});
}

示例用法:

    void *buf = alloc_array(cnt);
    T *arr = construct_array(buf,cnt);

    for(int i = 0; i < cnt; i++)
        T &ob = arr[i]; /* ... */

    destruct_array(arr,cnt);
    free_array(buf,cnt);

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...