std :: vector< std :: wstring>移动/重新分配内部wstring.data()是否合法? [英] std::vector<std::wstring> Is moving/reallocating inner wstring.data() legal?
问题描述
这是节选:
<代码> ...std :: vector< std :: wstring>vecWstr;vecWstr.emplace_back(L"1");wchar_t * data1 = vecWstr [0] .data();//<-此指针将来需要使用.vecWstr.emplace_back(L"2");wchar_t * data2 = vecWstr [0] .data();如果(data1!= data2)MessageBox(L错误,不相等.",L比较");
MessageBox
总是出现.
因此,在这里,我比较了 .emplace()
之前和之后的两个 wstring
缓冲区.以我的理解,它们必须相等.
这里主要关心的是:为什么 vector
在一秒钟后移动/重新分配了第一内部元素 std :: wstring
元素?
在进行了怪异的程序行为后进行了调查之后,出现了这个问题.
如果我在第二个 .emplace()之前保存
vecWstr [0] .data()
缓冲区指针,则缓冲区指针将变得过时并且程序的行为不当.
最大的问题是程序中有很多 std :: vector< std :: wstring>
,但它们似乎都按预期工作,到目前为止,只有一个如所示以上.
这一切都在 MSVS 16.1.5
问题是:
谁在这里? std :: vector
是否可以更改/移动其 std :: wstring
元素的内部缓冲区?
在C ++ STL中,有一些称为指针无效的东西.这意味着,当您获得容器中某个元素的指针,然后又修改了该容器时,在修改之后,您的指针可能不再有效.
指针无效的规则由标准定义,在容器与容器之间,操作与操作之间有所不同.
在您的情况下,您有一个 std :: vector
.如果您 emplace_back
并且向量需要更大的容量来添加元素,则对向量元素的引用/指针/迭代器将不再有效.在这种情况下,向量将在内存中分配另一个更大的空间,并将所有元素移到那里.
但是等等!
您是直接从字符串中获取 data()
指针!为什么此指针也无效? wstring
不应该是仅包含指向某些堆缓冲区的指针的轻量级结构吗?
好吧,这是SSO(小字符串优化)的魔力.如果您的字符串足够小,则 wstring
只会将其缓冲区存储在数据结构本身中(而不是存储指向缓冲区的指针).在这种情况下,当您移动它时,指针当然会失效.
您的字符串非常小(1个宽字符),因此它满足SSO的条件.如果您使用更长的版本:
std :: vector< std :: wstring>vecWstr;vecWstr.emplace_back(L"asdfghjkl");wchar_t * data1 = vecWstr [0] .data();//<-此指针将来需要使用.vecWstr.emplace_back(L"qwertyuiop");wchar_t * data2 = vecWstr [0] .data();如果(data1!= data2)MessageBox(0,L错误,不相等.",L比较",0);返回0;
该消息框可能不会弹出.
但是,您无法控制运行时字符串的长度,并且您不知道编译器将如何实现SSO,所以请不要这样编码! >
相反,您可以使用 The main concern here is: Why The question is: In C++ STL, there is something called pointer invalidation. This means, when you obtain a pointer of an element in a container, and later you modified the container, after the modification your pointer may be no longer valid. The rule of pointer invalidation is defined by the standard and varies between containers to containers, operations to operations. In your case, you have a But wait! You are taking Well, this is the magic of SSO (Small String Optimization). If your string is small enough, Your string is pretty small (1 wide char), so it satisfies the condition of SSO. If you use longer ones: The messagebox would probably not pop. However you don't have control over the length of the run-time string, and you don't know how your compiler would implement SSO, so don't code this way! Instead, you can use the 这篇关于std :: vector< std :: wstring>移动/重新分配内部wstring.data()是否合法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋! reserve
方法(如songyuanyao所建议),或使用其他在添加元素时不会使指针无效的容器.请参阅 std :: list 和...
std::vector<std::wstring> vecWstr;
vecWstr.emplace_back(L"1");
wchar_t* data1 = vecWstr[0].data(); //<-This pointer needed for future use.
vecWstr.emplace_back(L"2");
wchar_t* data2 = vecWstr[0].data();
if (data1 != data2)
MessageBox(L"Error, not equal.", L"Compare");
MessageBox
always arises.
So, here i compare two wstring
buffers before and after.emplace()
. In my understanding they must be equal.vector
moves/reallocates 1st innner std::wstring
element after emplacing a second?
This question arose after investigation took place after weird program behavior.
If i save vecWstr[0].data()
buffer pointer before second .emplace()
then buffer pointer becomes obsolete and program behaves inappropriately.
The biggest issue is that there are a lot of std::vector<std::wstring>
's in a program, but all of them seem to work as expected, and only one so far like showed above.
This is all in MSVS 16.1.5
Who is right here? Can std::vector
change/move the inner buffer of its std::wstring
elements or not?std::vector
. A reference/pointer/iterator to a vector element is no longer valid if you emplace_back
and vector needs bigger capacity for the added element. In this case, the vector allocate another bigger space in memory and moves all its elements there.data()
pointer directly from the string! Why is this pointer also invalidated? Shouldn't wstring
be a light-weight struct that just contains pointer to some heap buffer?wstring
just stores its buffer in the data structure itself (rather than storing a pointer to a buffer) . In this case, when you move it around, of course the pointer is invalidated.std::vector<std::wstring> vecWstr;
vecWstr.emplace_back(L"asdfghjkl");
wchar_t* data1 = vecWstr[0].data(); //<-This pointer needed for future use.
vecWstr.emplace_back(L"qwertyuiop");
wchar_t* data2 = vecWstr[0].data();
if (data1 != data2)
MessageBox(0, L"Error, not equal.", L"Compare", 0);
return 0;
reserve
method (as songyuanyao suggested), or use other containers that don't invalidate pointers when adding element. Please refer to std::list and std::deque. Read the sections about their pointer/reference/iterator invalidation.