Meh*_*dad 7 c++ swap bit-manipulation
您不应该将对象指针视为OOP语言(包括C++)中原始二进制数据的指针.对象"超过"它们的表示.
因此,例如,swap通过交换字节来处理两个对象是不正确的:
template<class T>
void bad_swap(T &a, T &b) // Assuming T is the most-derived type of the object
{
char temp[sizeof(T)];
memcpy(temp, &a, sizeof(a));
memcpy(&a, &b, sizeof(b));
memcpy(&b, temp, sizeof(temp));
}
Run Code Online (Sandbox Code Playgroud)
然而,唯一的情况是,我可以想象这个导致问题的快捷方式是当一个对象包含一个指向自身的指针时,我很少(从不?)在实践中看到它; 但是,也可能是其他情景.
swap如果你执行按位交换,什么是正确会破坏的实际(真实世界)示例?
我可以很容易地用自我指针提出人为的例子,但我想不出任何真实的例子.
Bo *_*son 13
这不是具体的,swap而是一个示例,表明低级别优化可能不值得麻烦.无论如何,编译器经常会想出来.
当然,这是我最喜欢的编译器非常幸运的例子,但无论如何我们不应该认为编译器是愚蠢的,并且我们可以通过一些简单的技巧轻松改进生成的代码.
我的测试代码是 - 构造一个std :: string并复制它.
std::string whatever = "abcdefgh";
std::string whatever2 = whatever;
Run Code Online (Sandbox Code Playgroud)
第一个构造函数看起来像这样
basic_string(const value_type* _String,
const allocator_type& _Allocator = allocator_type() ) : _Parent(_Allocator)
{
const size_type _StringSize = traits_type::length(_String);
if (_MySmallStringCapacity < _StringSize)
{
_AllocateAndCopy(_String, _StringSize);
}
else
{
traits_type::copy(_MySmallString._Buffer, _String, _StringSize);
_SetSmallStringCapacity();
_SetSize(_StringSize);
}
}
Run Code Online (Sandbox Code Playgroud)
生成的代码是
std::string whatever = "abcdefgh";
000000013FCC30C3 mov rdx,qword ptr [string "abcdefgh" (13FD07498h)]
000000013FCC30CA mov qword ptr [whatever],rdx
000000013FCC30D2 mov byte ptr [rsp+347h],0
000000013FCC30DA mov qword ptr [rsp+348h],8
000000013FCC30E6 mov byte ptr [rsp+338h],0
Run Code Online (Sandbox Code Playgroud)
这里traits_type::copy包含一个调用memcpy,它被优化为整个字符串的单个寄存器副本(仔细选择以适合).编译器还将调用strlen转换为编译时8.
然后我们将其复制到一个新的字符串中.复制构造函数看起来像这样
basic_string(const basic_string& _String)
: _Parent(std::allocator_traits<allocator_type>::select_on_container_copy_construction(_String._MyAllocator))
{
if (_MySmallStringCapacity < _String.size())
{
_AllocateAndCopy(_String);
}
else
{
traits_type::copy(_MySmallString._Buffer, _String.data(), _String.size());
_SetSmallStringCapacity();
_SetSize(_String.size());
}
}
Run Code Online (Sandbox Code Playgroud)
并且仅产生4个机器指令:
std::string whatever2 = whatever;
000000013FCC30EE mov qword ptr [whatever2],rdx
000000013FCC30F6 mov byte ptr [rsp+6CFh],0
000000013FCC30FE mov qword ptr [rsp+6D0h],8
000000013FCC310A mov byte ptr [rsp+6C0h],0
Run Code Online (Sandbox Code Playgroud)
请注意,优化器会记住char它们仍然在寄存器中rdx,并且字符串长度必须相同,8.
在看到这样的事情之后,我喜欢信任我的编译器,并避免尝试使用bit fiddling来改进代码.除非分析发现意外的瓶颈,否则它无济于事.
(以MSVC 10和我的std :: string实现为特色)
我将争辩说,这几乎总是一个坏主意,除非在特定情况下进行分析并且有更明显和明确的swap性能问题实现.即使在这种情况下,我也只会采用这种方法来直接进行无继承结构,从不用于任何类.你永远不知道什么时候会增加继承可能会破坏整个事情(也可能以真正阴险的方式).
如果你想要一个快速交换实现,或许更好的选择(在适当的情况下)是pimpl该类,然后只是交换实现(再次,这假设没有指向所有者的后向指针,但这很容易包含在类中&impl而不是外部因素).
编辑:这种方法可能出现的问题:
| 归档时间: |
|
| 查看次数: |
1200 次 |
| 最近记录: |