std::swap 丢失了 Type-Based 别名分析使用的信息?
std::swap loses information used by Type-Based Alias Analysis?
通过检查 vector
class 在 GCC headers (stl_vector.h
) 中的实现,我在 vector base 实现中发现了以下两个成员函数 class(我在示例中将其重命名为 Data_Class
以避免使用 long_and_weird 名称)。
void
_M_copy_data(Data_Class const& __x) _GLIBCXX_NOEXCEPT
{
_M_start = __x._M_start;
_M_finish = __x._M_finish;
_M_end_of_storage = __x._M_end_of_storage;
}
void
_M_swap_data(Data_Class& __x) _GLIBCXX_NOEXCEPT
{
// Do not use std::swap(_M_start, __x._M_start), etc as it loses
// information used by TBAA.
Data_Class __tmp;
__tmp._M_copy_data(*this);
_M_copy_data(__x);
__x._M_copy_data(__tmp);
}
成员 (_M_start
、_M_finish
、_M_end_of_storage
) 只是某种类型的指针,并且是 class.
中唯一的成员
这里的问题是第二个函数中出现注释的原因是什么?
可能是出于同样的原因,但为什么不使用 std::swap
用于两个 Data_Class
objects 或者至少使用一个自动生成的 operator=
来进行复制?
我觉得这可以做得更简单。
对于 std::vector
对象,包含的三个指针永远不会寻址与另一个 std::vector
中的指针相同的内存 - 每个管理自己的连续内存区域。这种洞察力可用于 type-based 别名优化,如果以编译器能够遵循和推理的方式移动各个指针,则这种优化将继续成为可能。
std::swap
可能会使用一些 in-place 按位欺骗来实现,这样编译器就无法执行该跟踪(参见 here),因此最好避免。
当然,没有什么本质上会阻止优化器能够跟踪 swap
所做的任何事情并将其识别为与 __tmp
-using 代码相同的逻辑操作,但无论谁发表了评论并且选择不使用 std::swap
可能观察到或推断出它在 至少 他们使用的编译器的一个版本上也没有针对某种优化级别进行优化。不过,更糟糕的优化可能很常见。
相同类型的 observation/reasoning 可能导致他们避免默认 operator=
。例如,假设他们的编译器上的实现可能类似于 memcpy
- 如果您将数据视为具有 char
类型,那么您可以安全地避免别名错误(同样的方式,您只能安全地排序访问不同的 union
成员是 char
或 char[]
),但那是因为别名优化被抑制了。
通过检查 vector
class 在 GCC headers (stl_vector.h
) 中的实现,我在 vector base 实现中发现了以下两个成员函数 class(我在示例中将其重命名为 Data_Class
以避免使用 long_and_weird 名称)。
void
_M_copy_data(Data_Class const& __x) _GLIBCXX_NOEXCEPT
{
_M_start = __x._M_start;
_M_finish = __x._M_finish;
_M_end_of_storage = __x._M_end_of_storage;
}
void
_M_swap_data(Data_Class& __x) _GLIBCXX_NOEXCEPT
{
// Do not use std::swap(_M_start, __x._M_start), etc as it loses
// information used by TBAA.
Data_Class __tmp;
__tmp._M_copy_data(*this);
_M_copy_data(__x);
__x._M_copy_data(__tmp);
}
成员 (_M_start
、_M_finish
、_M_end_of_storage
) 只是某种类型的指针,并且是 class.
这里的问题是第二个函数中出现注释的原因是什么?
可能是出于同样的原因,但为什么不使用 std::swap
用于两个 Data_Class
objects 或者至少使用一个自动生成的 operator=
来进行复制?
我觉得这可以做得更简单。
对于 std::vector
对象,包含的三个指针永远不会寻址与另一个 std::vector
中的指针相同的内存 - 每个管理自己的连续内存区域。这种洞察力可用于 type-based 别名优化,如果以编译器能够遵循和推理的方式移动各个指针,则这种优化将继续成为可能。
std::swap
可能会使用一些 in-place 按位欺骗来实现,这样编译器就无法执行该跟踪(参见 here),因此最好避免。
当然,没有什么本质上会阻止优化器能够跟踪 swap
所做的任何事情并将其识别为与 __tmp
-using 代码相同的逻辑操作,但无论谁发表了评论并且选择不使用 std::swap
可能观察到或推断出它在 至少 他们使用的编译器的一个版本上也没有针对某种优化级别进行优化。不过,更糟糕的优化可能很常见。
相同类型的 observation/reasoning 可能导致他们避免默认 operator=
。例如,假设他们的编译器上的实现可能类似于 memcpy
- 如果您将数据视为具有 char
类型,那么您可以安全地避免别名错误(同样的方式,您只能安全地排序访问不同的 union
成员是 char
或 char[]
),但那是因为别名优化被抑制了。