C++ std::string分析
std::string
typedef std::basic_string<char,std::char_traits<char>,std::allocator<char> > std::string;MSVC 实现
class std::string {
union {
char _Buf[16]; // stack-string
char* _Ptr; // heap-stirng
} _Bx;
unsigned __int64 _Mysize; // size
unsigned __int64 _Myres; // capacity
};SSO
Small String Optimization(SSO),小字符串优化,如果字符串很短(<=15),那么直接存到栈上,如果大于这个阈值,则存堆上。
15字节是因为,字符串需要一个\x00结尾,所以SSO总共16字节。
Assign
直接赋值
代码示例
std::string a;
a = "12345";
/* --Compilation--> */
std::string::_Assign<char>(&a, "12345", 5u);
// ??$_Assign@D@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEAAAEAV01@QEBD_K@Z
// std::string *__fastcall std__basic_string_char_std__char_traits_char__std__allocator_char_____Assign_char_(std::string *this, const char *const Ptr, unsigned __int64 Count);_Assign<char>实现
直接赋值时,传入一个const char* ptr和一个unsigned __int64 Count分别代表要赋值的字符串指针和字符串长度。
然后会先判断String的Capacity是否大于要赋值的字符串长度(也就是 Count <= cap + 1,始终保持有\x00结尾)。
如果Capacity较大,则直接进行memmove,不过需要判断capacity是否<=15,也就是是否为ShortString,然后move到栈/堆上。
如果Capacity较小,意味着需要进行扩容,扩容分下面几个步骤。
长度检查,需求长度首先对齐到16字节,并要求对齐后的长度
nlen不能超过有符号整数范围,避免ptrdiff_t溢出。使用贪婪策略计算长度,若
nlen小于1.5*cap,则更新长度到1.5*cap,否则nlen不变。检测
nlen+1是否小于1PageSize,若小于,则直接申请内存,保证了16字节对齐;若大于等于,则多分配40个字节内存,用于32字节对齐,随后对nlen+40进行overflow检查,然后分配nlen+40长度的内存,并使用((alignedNewMalloc + 39) & 0xFFFFFFFFFFFFFFE0uLL)寻找分配内存中的第一个32字节对齐点,并把原始地址埋入这之前8字节的内容。也就是说,多分配的40字节内存中,32字节是为了处理对齐,剩下8字节则编码了malloc返回的未32字节对齐的地址。到达endMalloc环节,更新String参数的Capacity和Size,并将新文本拷贝过来,在末尾补0。
若先前的cap<=0xF,则之前是短字符串,就把堆指针放入开头,由于在栈上,就不需要对之前的字符串进行释放了。
若先前的cap>0xF,则之前是非短字符串,在堆上,需要对其进行释放,一样的,先看是否是小于一个页(16字节对齐),若是,则直接释放,若非,则是32字节对齐,取到它埋入真实数据前面的8个字节的真实地址,检测完后(防止真实地址被恶意修改到其他位置,导致堆利用),进行释放即可。
最后,这个函数会返回std::string的指针,方便链式调用。
std::string *__fastcall std::string::_Assign<char>(std::string *this, const char *const Ptr, unsigned __int64 Count)
{
unsigned __int64 cap; // rbp
std::string *ssoString; // rdi
unsigned __int64 nlen; // rdi
__int64 capHalfLen; // rdx
char *newMalloc; // r14
size_t aligned; // rcx
uint64_t alignedNewMalloc; // rax
char *ptrOld; // rcx
unsigned __int64 OldSize; // rdx
char *ptrRealOld; // rax
cap = this->_Mypair._Myval2._Myres;
if ( Count > cap )
{
nlen = 0x7FFFFFFFFFFFFFFFLL; // 初始化的值大于 capacity, 需要重新分配
if ( Count > 0x7FFFFFFFFFFFFFFFLL )
std::_Xlen_string(); // string too long
if ( (Count | 0xF) > 0x7FFFFFFFFFFFFFFFLL || (capHalfLen = cap >> 1, cap > 0x7FFFFFFFFFFFFFFFLL - (cap >> 1)) )
{ // Count | 0xf 计算了十六字节对齐后的大小,还为最后留了一个\x00的位置。
// 后半段在计算1.5倍扩容是否会超出最大大小
aligned = 0x8000000000000027LL; // 如果超出2^63,无法分配,设置一个很大的值。
}
else
{
nlen = Count | 0xF;
if ( (Count | 0xF) < capHalfLen + cap ) // pad(count) < 1.5 cap
nlen = capHalfLen + cap; // 如果1.5cap容量就够了,就申请1.5cap(贪婪策略)
if ( nlen == 0xFFFFFFFFFFFFFFFFuLL ) // 检测会不会overflow,导致malloc(-1)
{
newMalloc = 0; // 分配失败
goto endMalloc;
}
if ( nlen + 1 < 0x1000 ) // 如果申请量刚好等于4KB(1 PageSize), 则不需要经过其他对齐,直接分配即可。
{
newMalloc = (char *)operator new(nlen + 1);// <4KB,只保证返回值16字节对齐,不保证32字节对齐。
goto endMalloc;
}
aligned = nlen + 40; // 多分配40个字节,为了32字节对齐,还有埋入一个初始地址。
if ( nlen + 40 < nlen + 1 ) // overflow
__scrt_throw_std_bad_array_new_length();
}
alignedNewMalloc = (uint64_t)operator new(aligned);
if ( !alignedNewMalloc )
goto LABEL_24;
newMalloc = (char *)((alignedNewMalloc + 39) & 0xFFFFFFFFFFFFFFE0uLL);// 从开头开始,寻找32字节对齐的地址(0b1111....1100000)
*((_QWORD *)newMalloc - 1) = alignedNewMalloc;// 在正式数据之前埋入new返回的地址,用于free。
endMalloc:
this->_Mypair._Myval2._Mysize = Count; // 更新string参数
this->_Mypair._Myval2._Myres = nlen;
memcpy_0(newMalloc, Ptr, Count); // 把当前内容拷贝过去
newMalloc[Count] = 0; // 保证最后的是\x00
if ( cap <= 0xF ) // 如果旧的string是shortstring
{
LABEL_27:
this->_Mypair._Myval2._Bx._Ptr = newMalloc;// 直接覆盖掉前面的值,变成ptr。
return this;
}
ptrOld = this->_Mypair._Myval2._Bx._Ptr; // 如果旧的string是在堆上的,就要free旧的。
OldSize = cap + 1;
if ( cap + 1 < 0x1000 ) // 在一个页内
{
ptrRealOld = this->_Mypair._Myval2._Bx._Ptr;// 直接返回,因为没有32字节对齐。
goto LABEL_26;
}
ptrRealOld = (char *)*((_QWORD *)ptrOld - 1);// 取到真正的初始化地址,因为32字节对齐。
if ( (unsigned __int64)(ptrOld - ptrRealOld - 8) <= 0x1F )// 防止ptrRealOld被恶意修改,进行检测
{
OldSize = cap + 40;
LABEL_26:
operator delete(ptrRealOld, OldSize);
goto LABEL_27;
}
LABEL_24:
__fastfail(5u); // ptrRealOld 损坏
}
if ( cap <= 0xF ) // 如果cap小于等于15,这里也就确认了count<=15
ssoString = this;
else
ssoString = (std::string *)this->_Mypair._Myval2._Bx._Ptr;
this->_Mypair._Myval2._Mysize = Count;
memmove_0(ssoString, Ptr, Count);
ssoString->_Mypair._Myval2._Bx._Buf[Count] = 0;// 直接移动过去即可
return this;
}std::cout
对于字符串.c_str()后进行输出,则会判断其是否为短字符,如果不是短字符,则提前解引用一层。
std::cout << a.c_str();
/* --Compliation--> */
p_a = &a;
if ( a._Mypair._Myval2._Myres > 0xF )
p_a = (std::string *)a._Mypair._Myval2._Bx._Ptr;
std::operator<<<std::char_traits<char>>(std::cout, p_a->_Mypair._Myval2._Bx._Buf);若是直接输出字符串进行输出,则使用_Insert_string将字符串插入到输出流中,与上面不同的是,_Insert_string传入了字符串长度,而上面则是通过strlen重新获取了字符串长度,且使用_Insert_string可以得益于对String的优化(16/32字节对齐),而进行快速拷贝。
std::cout << a;
/* --Compliation--> */
std::_Insert_string<char,std::char_traits<char>,unsigned __int64>(
std::cout,
Ptr->_Mypair._Myval2._Bx._Buf,
a._Mypair._Myval2._Mysize);
std::ostream::operator<<(std::cout, a._Mypair._Myval2._Mysize);operator<<<char_traits<char>>
// Hidden C++ exception states: #wind=3
std::ostream *__fastcall std::operator<<<std::char_traits<char>>(std::ostream *Ostr, const char *Val)
{
std::ostream *v3; // rsi
unsigned int v4; // ebx
signed __int64 v5; // rax
signed __int64 v6; // r15
__int64 v7; // r9
__int64 v8; // rdi
__int64 v9; // rdi
std::ostream *v10; // r14
__int64 v11; // rcx
bool v12; // al
std::ostream *v13; // rcx
__int64 v14; // rdx
__int64 v15; // r8
__int64 v16; // rcx
std::ostream *_Ok; // [rsp+20h] [rbp-38h]
int _State; // [rsp+70h] [rbp+18h]
v3 = Ostr;
v4 = 0;
_State = 0;
v5 = strlen_0(Val);
v6 = v5;
v7 = *(int *)(*(_QWORD *)v3->gap0 + 4LL);
v8 = *(_QWORD *)&v3->gap0[v7 + 40];
if ( v8 <= 0 || v8 <= v5 )
v9 = 0;
else
v9 = v8 - v5;
v10 = v3;
_Ok = v3;
v11 = *(_QWORD *)&v3->gap0[v7 + 72];
if ( v11 )
(*(void (__fastcall **)(__int64))(*(_QWORD *)v11 + 8LL))(v11);
v12 = std::ios_base::good((std::ios_base *)&v3->gap0[*(int *)(*(_QWORD *)v3->gap0 + 4LL)]);
if ( v12 )
{
v13 = *(std::ostream **)&v3->gap0[*(int *)(*(_QWORD *)v3->gap0 + 4LL) + 80];
if ( !v13 || v13 == v3 )
{
v12 = 1;
}
else
{
std::ostream::flush();
v12 = std::ios_base::good((std::ios_base *)&v3->gap0[*(int *)(*(_QWORD *)v3->gap0 + 4LL)]);
}
}
if ( v12 )
{
try
{
v14 = *(_QWORD *)v3->gap0;
if ( (*(_DWORD *)&v3->gap0[*(int *)(*(_QWORD *)v3->gap0 + 4LL) + 24] & 0x1C0) != 0x40 )
{
while ( v9 > 0 )
{
if ( (unsigned int)std::streambuf::sputc(
*(_QWORD *)&v3->gap0[*(int *)(*(_QWORD *)v3->gap0 + 4LL) + 72],
(unsigned __int8)v3->gap0[*(int *)(*(_QWORD *)v3->gap0 + 4LL) + 88]) == -1 )
goto LABEL_23;
--v9;
}
v14 = *(_QWORD *)v3->gap0;
}
if ( std::streambuf::sputn(*(_QWORD *)&v3->gap0[*(int *)(v14 + 4) + 72], Val, v6) == v6 )
{
while ( v9 > 0 )
{
if ( (unsigned int)std::streambuf::sputc(
*(_QWORD *)&v3->gap0[*(int *)(*(_QWORD *)v3->gap0 + 4LL) + 72],
(unsigned __int8)v3->gap0[*(int *)(*(_QWORD *)v3->gap0 + 4LL) + 88]) == -1 )
goto LABEL_23;
--v9;
}
}
else
{
LABEL_23:
v4 = 4;
_State = 4;
}
*(_QWORD *)&v3->gap0[*(int *)(*(_QWORD *)v3->gap0 + 4LL) + 40] = 0;
}
catch ( ... )
{
LOBYTE(v15) = 1;
std::ios::setstate(&Ostr->gap0[*(int *)(*(_QWORD *)Ostr->gap0 + 4LL)], 4, v15);
v3 = Ostr;
v4 = _State;
v10 = _Ok;
}
}
else
{
v4 = 4;
}
std::ios::setstate(&v3->gap0[*(int *)(*(_QWORD *)v3->gap0 + 4LL)], v4, 0);
if ( !std::uncaught_exceptions() )
std::ostream::_Osfx(v10);
v16 = *(_QWORD *)&v10->gap0[*(int *)(*(_QWORD *)v10->gap0 + 4LL) + 72];
if ( v16 )
(*(void (__fastcall **)(__int64))(*(_QWORD *)v16 + 16LL))(v16);
return v3;
}Size
Size和Length一样,都是直接返回Size而不是进行strlen。
a.size();
/* --Compliation--> */
a._Mypair._Myval2._Mysize;_NODISCARD _CONSTEXPR20 size_type length() const noexcept {
return _Mypair._Myval2._Mysize;
}
_NODISCARD _CONSTEXPR20 size_type size() const noexcept {
return _Mypair._Myval2._Mysize;
}Push_Back
C++的string push_back比较繁琐,首先判断Size是否等于Capacity,这样的话,就需要重新分配。
_CONSTEXPR20 void push_back(const _Elem _Ch) { // insert element at end
const size_type _Old_size = _Mypair._Myval2._Mysize;
if (_Old_size < _Mypair._Myval2._Myres) {
_ASAN_STRING_MODIFY(*this, _Old_size, _Old_size + 1);
_Mypair._Myval2._Mysize = _Old_size + 1;
_Elem* const _Ptr = _Mypair._Myval2._Myptr();
_Traits::assign(_Ptr[_Old_size], _Ch);
_Traits::assign(_Ptr[_Old_size + 1], _Elem());
return;
}
_Reallocate_grow_by(
1,
[](_Elem* const _New_ptr, const _Elem* const _Old_ptr, const size_type _Old_size, const _Elem _Ch)
_STATIC_LAMBDA {
_Traits::copy(_New_ptr, _Old_ptr, _Old_size);
_Traits::assign(_New_ptr[_Old_size], _Ch);
_Traits::assign(_New_ptr[_Old_size + 1], _Elem());
},
_Ch);
}v11 = a._Mypair._Myval2._Mysize;
if ( a._Mypair._Myval2._Mysize >= a._Mypair._Myval2._Myres )
{
____Reallocate_grow_by_V_lambda_1___1__push_back___basic_string_DU__char_traits_D_std__V__allocator_D_2__std__QEAAXD_Z_D___basic_string_DU__char_traits_D_std__V__allocator_D_2__std__AEAAAEAV01__KV_lambda_1___1__push_back_01_QEAAXD_Z_D_Z(
&a,
a._Mypair._Myval2._Myres,
v10,
'1');
}
else
{
++a._Mypair._Myval2._Mysize;
v12 = &a;
if ( a._Mypair._Myval2._Myres > 0xF )
v12 = (std::string *)a._Mypair._Myval2._Bx._Ptr;
*(_WORD *)&v12->_Mypair._Myval2._Bx._Buf[v11] = '1';
}然后就是扩容函数,这个和Assign很相似,不同点在于,这个函数默认1.5倍扩大,Count=1,且仅把_Fn一个字符放进最后。
std::string *__fastcall ____Reallocate_grow_by_V_lambda_1___1__push_back___basic_string_DU__char_traits_D_std__V__allocator_D_2__std__QEAAXD_Z_D___basic_string_DU__char_traits_D_std__V__allocator_D_2__std__AEAAAEAV01__KV_lambda_1___1__push_back_01_QEAAXD_Z_D_Z(
std::string *this,
const unsigned __int64 <_Args_0>,
std::string::push_back::__l2::<lambda_1> _Size_increase,
char _Fn)
{
size_t Mysize; // r14
unsigned __int64 v5; // rbx
unsigned __int64 Myres; // r15
unsigned __int64 v9; // rcx
unsigned __int64 v10; // rdx
_QWORD *v11; // rdi
unsigned __int64 v12; // rcx
void *v13; // rax
char *Ptr; // rbx
_BYTE *v15; // rcx
Mysize = this->_Mypair._Myval2._Mysize;
v5 = 0x7FFFFFFFFFFFFFFFLL;
if ( Mysize == 0x7FFFFFFFFFFFFFFFLL )
std::_Xlen_string();
Myres = this->_Mypair._Myval2._Myres;
v9 = (Mysize + 1) | 0xF;
if ( v9 > 0x7FFFFFFFFFFFFFFFLL || (v10 = Myres >> 1, Myres > 0x7FFFFFFFFFFFFFFFLL - (Myres >> 1)) )
{
v12 = 0x8000000000000027uLL;
}
else
{
v5 = (Mysize + 1) | 0xF;
if ( v9 < Myres + v10 )
v5 = Myres + v10;
if ( v5 == -1 )
{
v11 = 0;
goto LABEL_15;
}
if ( v5 + 1 < 0x1000 )
{
v11 = operator new(v5 + 1);
goto LABEL_15;
}
v12 = v5 + 40;
if ( v5 + 40 < v5 + 1 )
__scrt_throw_std_bad_array_new_length();
}
v13 = operator new(v12);
if ( !v13 )
goto LABEL_19;
v11 = (_QWORD *)(((unsigned __int64)v13 + 39) & 0xFFFFFFFFFFFFFFE0uLL);
*(v11 - 1) = v13;
LABEL_15:
this->_Mypair._Myval2._Mysize = Mysize + 1;
this->_Mypair._Myval2._Myres = v5;
if ( Myres <= 0xF )
{
memcpy_0(v11, this, Mysize);
*((_BYTE *)v11 + Mysize) = _Fn;
*((_BYTE *)v11 + Mysize + 1) = 0;
goto LABEL_22;
}
Ptr = this->_Mypair._Myval2._Bx._Ptr;
memcpy_0(v11, this->_Mypair._Myval2._Bx._Ptr, Mysize);
*((_BYTE *)v11 + Mysize) = _Fn;
*((_BYTE *)v11 + Mysize + 1) = 0;
if ( Myres + 1 < 0x1000 )
{
operator delete(Ptr, Myres + 1);
goto LABEL_22;
}
v15 = (_BYTE *)*((_QWORD *)Ptr - 1);
if ( (unsigned __int64)(Ptr - v15 - 8) > 0x1F )
LABEL_19:
__fastfail(5u);
operator delete(v15, Myres + 40);
LABEL_22:
this->_Mypair._Myval2._Bx._Ptr = (char *)v11;
return this;
}Append
Append(const char*)
这种情况,扩容提供两个参数,一个长度一个指针。
Mysize = a._Mypair._Myval2._Mysize;
v7 = &a;
if ( a._Mypair._Myval2._Myres == a._Mypair._Myval2._Mysize )
{
appended = ____Reallocate_grow_by_V_lambda_1___1_____Append_D___basic_string_DU__char_traits_D_std__V__allocator_D_2__std__AEAAAEAV23_QEBD_K_Z_PEBD_K___basic_string_DU__char_traits_D_std__V__allocator_D_2__std__AEAAAEAV01__KV_lambda_1___1_____Append_D_01_AEAAAEAV01_QEBD0_Z_PEBD_K_Z(
&a,
1u,
(std::string::_Append::__l2::<lambda_1>)a._Mypair._Myval2._Myres,
v5,
1u);
}
else
{
++a._Mypair._Myval2._Mysize;
if ( a._Mypair._Myval2._Myres > 0xF )
v7 = (std::string *)a._Mypair._Myval2._Bx._Ptr;
strcpy(&v7->_Mypair._Myval2._Bx._Buf[Mysize], "1");
appended = &a;
}Sizeincrease和_Fn其实一样,前者更像逻辑上的增量,而后者是给memcpy看的,具体要拷贝过来多少字节。
std::string *__fastcall ____Reallocate_grow_by_V_lambda_1___1_____Append_D___basic_string_DU__char_traits_D_std__V__allocator_D_2__std__AEAAAEAV23_QEBD_K_Z_PEBD_K___basic_string_DU__char_traits_D_std__V__allocator_D_2__std__AEAAAEAV01__KV_lambda_1___1_____Append_D_01_AEAAAEAV01_QEBD0_Z_PEBD_K_Z(
std::string *this,
size_t _Size_increase,
std::string::_Append::__l2::<lambda_1> <_Args_1>,
const char *a4,
size_t _Fn)
{
size_t Mysize; // r15
unsigned __int64 v6; // rbx
unsigned __int64 v8; // rbp
unsigned __int64 Myres; // r14
unsigned __int64 v10; // rcx
unsigned __int64 v11; // rdx
_QWORD *v12; // rdi
unsigned __int64 v13; // rcx
void *v14; // rax
char *v15; // r12
char *Ptr; // rbx
_BYTE *v17; // rcx
Mysize = this->_Mypair._Myval2._Mysize;
v6 = 0x7FFFFFFFFFFFFFFFLL;
if ( 0x7FFFFFFFFFFFFFFFLL - Mysize < _Size_increase )
std::_Xlen_string();
v8 = Mysize + _Size_increase;
Myres = this->_Mypair._Myval2._Myres;
v10 = (Mysize + _Size_increase) | 0xF;
if ( v10 > 0x7FFFFFFFFFFFFFFFLL || (v11 = Myres >> 1, Myres > 0x7FFFFFFFFFFFFFFFLL - (Myres >> 1)) )
{
v13 = 0x8000000000000027uLL;
}
else
{
v6 = v10;
if ( v10 < Myres + v11 )
v6 = Myres + v11;
if ( v6 == -1 )
{
v12 = 0;
goto LABEL_15;
}
if ( v6 + 1 < 0x1000 )
{
v12 = operator new(v6 + 1);
goto LABEL_15;
}
v13 = v6 + 40;
if ( v6 + 40 < v6 + 1 )
__scrt_throw_std_bad_array_new_length();
}
v14 = operator new(v13);
if ( !v14 )
goto LABEL_19;
v12 = (_QWORD *)(((unsigned __int64)v14 + 39) & 0xFFFFFFFFFFFFFFE0uLL);
*(v12 - 1) = v14;
LABEL_15:
this->_Mypair._Myval2._Mysize = v8;
v15 = (char *)v12 + Mysize;
this->_Mypair._Myval2._Myres = v6;
if ( Myres <= 0xF )
{
memcpy_0(v12, this, Mysize);
memcpy_0((char *)v12 + Mysize, "1", _Fn);
v15[_Fn] = 0;
goto LABEL_22;
}
Ptr = this->_Mypair._Myval2._Bx._Ptr;
memcpy_0(v12, this->_Mypair._Myval2._Bx._Ptr, Mysize);
memcpy_0((char *)v12 + Mysize, "1", _Fn);
v15[_Fn] = 0;
if ( Myres + 1 < 0x1000 )
{
operator delete(Ptr, Myres + 1);
goto LABEL_22;
}
v17 = (_BYTE *)*((_QWORD *)Ptr - 1);
if ( (unsigned __int64)(Ptr - v17 - 8) > 0x1F )
LABEL_19:
__fastfail(5u);
operator delete(v17, Myres + 40);
LABEL_22:
this->_Mypair._Myval2._Bx._Ptr = (char *)v12;
return this;
}std::wstring
MSVC实现
Assign
与std::string不同,std::wstring将Count进行8字节对齐,因为宽字符在Windows下是2字节一个,所以后续处理*2依旧保证其16字节对齐。
std::wstring *__fastcall std::wstring::_Assign<wchar_t>(
std::wstring *this,
const wchar_t *const _Ptr,
unsigned __int64 _Count)
{
unsigned __int64 Myres; // rbp
std::wstring *v7; // rsi
unsigned __int64 v8; // rbx
unsigned __int64 v10; // rbx
__int64 v11; // rdx
unsigned __int64 v12; // rcx
_QWORD *v13; // rsi
void *v14; // rax
wchar_t *Ptr; // rax
unsigned __int64 v16; // rdx
void *v17; // rcx
Myres = this->_Mypair._Myval2._Myres;
if ( _Count > Myres )
{
v10 = 0x7FFFFFFFFFFFFFFELL;
if ( _Count > 0x7FFFFFFFFFFFFFFELL )
std::_Xlen_string();
if ( (_Count | 7) > 0x7FFFFFFFFFFFFFFELL || (v11 = Myres >> 1, Myres > 0x7FFFFFFFFFFFFFFELL - (Myres >> 1)) )
{
v12 = -2;
}
else
{
v10 = _Count | 7;
if ( (_Count | 7) < v11 + Myres )
v10 = v11 + Myres;
if ( v10 + 1 > 0x7FFFFFFFFFFFFFFFLL )
goto LABEL_29;
v12 = 2 * (v10 + 1);
if ( !v12 )
{
v13 = 0;
goto LABEL_21;
}
}
if ( v12 < 0x1000 )
{
v13 = operator new(v12);
goto LABEL_21;
}
if ( v12 + 39 >= v12 )
{
v14 = operator new(v12 + 39);
if ( !v14 )
goto LABEL_25;
v13 = (_QWORD *)(((unsigned __int64)v14 + 39) & 0xFFFFFFFFFFFFFFE0uLL);
*(v13 - 1) = v14;
LABEL_21:
this->_Mypair._Myval2._Myres = v10;
this->_Mypair._Myval2._Mysize = _Count;
memcpy_0(v13, _Ptr, 2 * _Count);
*((_WORD *)v13 + _Count) = 0;
if ( Myres > 7 )
{
Ptr = this->_Mypair._Myval2._Bx._Ptr;
v16 = 2 * Myres + 2;
if ( v16 >= 0x1000 )
{
v17 = (void *)*((_QWORD *)Ptr - 1);
if ( (unsigned __int64)((char *)Ptr - (_BYTE *)v17 - 8) <= 0x1F )
{
operator delete(v17, 2 * Myres + 41);
this->_Mypair._Myval2._Bx._Ptr = (wchar_t *)v13;
return this;
}
LABEL_25:
__fastfail(5u);
}
operator delete(Ptr, v16);
}
this->_Mypair._Myval2._Bx._Ptr = (wchar_t *)v13;
return this;
}
LABEL_29:
__scrt_throw_std_bad_array_new_length();
}
if ( Myres <= 7 )
v7 = this;
else
v7 = (std::wstring *)this->_Mypair._Myval2._Bx._Ptr;
v8 = _Count;
this->_Mypair._Myval2._Mysize = _Count;
memmove_0(v7, _Ptr, 2 * _Count);
v7->_Mypair._Myval2._Bx._Buf[v8] = 0;
return this;
}