[英]Is this C++ ref example buggy?
I was checking aligned_storage
in cppref , but I think its example is buggy.我正在检查
aligned_storage
中的aligned_storage ,但我认为它的例子有问题。 Here is the code:这是代码:
#include <iostream>
#include <type_traits>
#include <string>
template<class T, std::size_t N>
class static_vector
{
// properly aligned uninitialized storage for N T's
typename std::aligned_storage<sizeof(T), alignof(T)>::type data[N];
std::size_t m_size = 0;
public:
// Create an object in aligned storage
template<typename ...Args> void emplace_back(Args&&... args)
{
if( m_size >= N ) // possible error handling
throw std::bad_alloc{};
// construct value in memory of aligned storage
// using inplace operator new
new(&data[m_size]) T(std::forward<Args>(args)...);
++m_size;
}
// Access an object in aligned storage
const T& operator[](std::size_t pos) const
{
// note: needs std::launder as of C++17
return *reinterpret_cast<const T*>(&data[pos]);
}
// Delete objects from aligned storage
~static_vector()
{
for(std::size_t pos = 0; pos < m_size; ++pos) {
// note: needs std::launder as of C++17
reinterpret_cast<T*>(&data[pos])->~T();
}
}
};
int main()
{
static_vector<std::string, 10> v1;
v1.emplace_back(5, '*');
v1.emplace_back(10, '*');
std::cout << v1[0] << '\n' << v1[1] << '\n';
}
Here we want to create a static vector that uses placement new .在这里,我们要创建一个使用放置 new的静态向量。 The problem is that
typename std::aligned_storage<sizeof(T), alignof(T)>::type
type is POD, not T
.问题是
typename std::aligned_storage<sizeof(T), alignof(T)>::type
type 是 POD,而不是T
。 so we need to cast it before using.所以我们需要在使用前投射它。 I think code should be something like this:
我认为代码应该是这样的:
#include <iostream>
#include <type_traits>
#include <string>
template<class T, std::size_t N>
class static_vector
{
// properly aligned uninitialized storage for N T's
typename std::aligned_storage<sizeof(T), alignof(T)>::type data[N];
T* data_ptr = reinterpret_cast<T*>(data);
std::size_t m_size = 0;
public:
// Create an object in aligned storage
template<typename ...Args> void emplace_back(Args&&... args)
{
if( m_size >= N ) // possible error handling
throw std::bad_alloc{};
// construct value in memory of aligned storage
// using inplace operator new
new(&data_ptr[m_size]) T(std::forward<Args>(args)...);
++m_size;
}
// Access an object in aligned storage
const T& operator[](std::size_t pos) const
{
// note: needs std::launder as of C++17
return *reinterpret_cast<const T*>(&data_ptr[pos]);
}
// Delete objects from aligned storage
~static_vector()
{
for(std::size_t pos = 0; pos < m_size; ++pos) {
// note: needs std::launder as of C++17
reinterpret_cast<T*>(&data_ptr[pos])->~T();
}
}
};
int main()
{
static_vector<std::string, 10> v1;
v1.emplace_back(5, '*');
v1.emplace_back(10, '*');
std::cout << v1[0] << '\n' << v1[1] << '\n';
}
Am I right?我对吗? Although I don't know why original code works in clang.
虽然我不知道为什么原始代码在 clang 中有效。
Update:更新:
Let me be more specific.让我说得更具体一点。 By standard,
aligned_storage
type is POD not T
.按照标准,
aligned_storage
类型是 POD 而不是T
。 so its implementation can be as following:所以它的实现可以如下:
template<std::size_t Len, std::size_t Align /* default alignment not implemented */>
struct aligned_storage {
struct type {
alignas(Align) unsigned char data[Len];
};
};
Now if you access this with data[pos]
, address will be increased based on unsigned char
size=1, not sizeof(T)
isn't it?现在,如果您使用
data[pos]
访问它,地址将根据unsigned char
size=1 增加,而不是sizeof(T)
不是吗?
typename std::aligned_storage<sizeof(T), alignof(T)>::type data[N];
You seem to think that &data[i]
will return the address of i-th byte in this array, while in reality it will return the address of i * sizeof(std::aligned_storage<sizeof(T), alignof(T)>)
th byte, which is the same as i * sizeof(T)
th byte.你似乎认为
&data[i]
会返回这个数组中第 i 个字节的地址,而实际上它会返回i * sizeof(std::aligned_storage<sizeof(T), alignof(T)>)
th 字节,与i * sizeof(T)
th 字节相同。 Example.例子。
OP: The problem is that in
aligned_storage
data is allocated in for exampleunsigned char
not typeT
.OP:问题在于,在
aligned_storage
数据被分配在例如unsigned char
而不是类型T
。 so when you are using&a[i]
it access members assuming each member size is1
(pointer wasunsigned char
) notsizeof(T)
.因此,当您使用
&a[i]
它访问成员,假设每个成员大小为1
(指针为unsigned char
)而不是sizeof(T)
。
This is not how it works.这不是它的工作原理。 It doesn't matter what type
aligned_storage
uses under the hood, unsigned char[N]
or something else.什么类型的
aligned_storage
在引擎盖下使用什么类型, unsigned char[N]
或其他东西都没有关系。
For brevity, let's use using A = std::aligned_storage<sizeof(T), alignof(T)>::type;
为简洁起见,让我们使用
using A = std::aligned_storage<sizeof(T), alignof(T)>::type;
. .
The array data
has type A[N]
.数组
data
类型为A[N]
。 When you apply operator []
to it, it decays to a pointer of type A *
.当您对其应用 operator
[]
时,它会衰减为A *
类型的指针。
data[i]
is equivalent to *(data + i)
. data[i]
等价于*(data + i)
。 When adding an integer to a pointer, the integer is multiplied by sizeof
of the pointed type.将整数添加到指针时,整数乘以
sizeof
类型的sizeof
。 The pointed type is A
, so sizeof(A)
is used (which is equal to sizeof(T)
).尖头类型是
A
,因此使用sizeof(A)
(等于sizeof(T)
)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.