考虑以下两个函数:
template<typename T, typename S>
void swap1(T* t, S* s)
{
static_assert(sizeof(T) == sizeof(S));
char tmp[sizeof(T)];
std::memcpy(tmp, t, sizeof(T));
std::memcpy(t, s, sizeof(T));
std::memcpy(s, tmp, sizeof(T));
}
和
template<typename T, typename S>
void swap2(T* t, S* s)
{
static_assert(sizeof(T) == sizeof(S));
char *tc = (char*)t, *sc = (char*)s;
std::swap_ranges(tc, tc + sizeof(T), sc);
}
哪一个违反了严格的别名规则?这两个人都违反了规则吗?如果两者都有,如何达到目标而不违反?
我从C标准中所能看到的是,我们可以使用某些类型的指针,包括char*
来指向任意对象,并访问其存储值。access是什么意思是读还是读+写**?
我没有从What is the Strict Aliasing Rule and Why do we care?找到答案。关于Hacker News - memcpy certainly violates aliasing rules的讨论让我更加困惑。
但是通过阅读Understanding C/C++ Strict Aliasing的“memcpy版本,符合C和C规范和高效”部分,似乎至少swap2
是完全好的。
1条答案
按热度按时间fdbelqdn1#
这两种实现都没有违反 * 严格的别名规则 *。规则禁止通过
U*
阅读或写入T*
,除非U*
是char*
/unsigned char*
/std::byte*
。通过char*
进行阅读和写是完全标准的C++。这个对象最终是否有价值是另一回事。我不认为标准保证任何东西,除非
T
和U
是相同的类型。也许除了一些算术转换。但我不确定。如果你只有一个简单的可复制类型
T
,[basic.types]/2说(省略一些细节):对于任何物体…可复制的
T
字体底层的字节可以将组成对象的数组复制到char
.如果该数组的内容被复制回对象,则该对象随后将保持其原始值。