考虑以下两个函数:
template<typename T, typename S>
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 = t, *sc = s;
std::swap_ranges(tc, tc + sizeof(T), sc);
}
其中哪一个违反了严格的别名规则?两人都违反规定了吗?如果两者兼而有之,如何在不违规的情况下达到目的?
我从C++标准中可以看到的是,我们可以使用某些类型的指针,包括
char*
来指向任意对象,并访问其存储的值。 访问是什么意思?只是读还是读+写?
我没有从这篇文章中找到明确的答案。
关于这篇文章的讨论让我更加困惑。
但是通过阅读这篇文章的“memcpy版本,符合C和C++规范并且高效”部分,看起来至少
swap2
是完全没问题的。
这两种实现都没有违反严格的别名规则。该规则禁止通过
T*
读取或写入 U*
,除非 U*
是 char*
/unsigned char*
/std::byte*
。通过 char*
进行读写是完美的标准 C++。
该对象最终是否具有一定的价值则完全是另一回事。我认为标准不能保证任何事情,除非
T
和 U
是同一类型。也许禁止一些算术转换。但我不确定。
如果你只有一个简单的可复制类型
T
,[basic.types]/2说(省略一些细节):
对于任何可普通复制类型的对象...
...组成对象的底层字节...可以复制到T
...的数组中 如果该数组的内容被复制回对象中,则该对象随后应保留其原始值。char