关于 CppCon 的talk分配器后,我遇到了following piece of code:
#include <iostream>
#include <string>
#include <utility>
#include <vector>
namespace {
template <typename T>
class MyAllocator {
public:
using value_type = T;
MyAllocator(std::string iType) : _type(std::move(iType)) {}
T* allocate(const std::size_t iNo) { return new T[iNo]; }
void deallocate(T* iPtr, const std::size_t) { delete[] iPtr; }
constexpr bool operator!=(const MyAllocator& oth) const {
return _type != oth._type;
}
const std::string& getType() const noexcept { return _type; }
private:
std::string _type;
};
using MyString =
std::basic_string<char, std::char_traits<char>, MyAllocator<char>>;
} // anonymous namespace
int main(int, char**) {
::MyString str1(::MyAllocator<char>("ForStr1"));
::MyString str2(::MyAllocator<char>("ForStr2"));
::MyString str3(::MyAllocator<char>("ForStr3"));
std::vector<::MyString> aVector;
aVector.reserve(1024);
aVector.push_back(str1);
aVector.push_back(str2);
std::cout << "[0]: " << aVector[0].get_allocator().getType() << "\n"
<< "[1]: " << aVector[1].get_allocator().getType() << "\n";
aVector.insert(aVector.begin(), str3);
const auto& type0 = aVector[0].get_allocator().getType();
const auto& type1 = aVector[1].get_allocator().getType();
const auto& type2 = aVector[2].get_allocator().getType();
std::cout << "[0]: " << type0 << "\n"
<< "[1]: " << type1 << "\n"
<< "[2]: " << type2 << "\n";
return 0;
}
我想这里的一般主题是关于嵌套容器中的&#34; 分配器&#34;。虽然从功能上讲,我遇到了问题,但我无法理解代码中发生了什么。
在代码中,我们有一个自定义的 allocator ,它本质上就像默认的分配器,除了它在内部存储一种数据。
我使用相同分配器的三个不同实例构建三个不同的字符串:
using MyString =
std::basic_string<char, std::char_traits<char>, MyAllocator<char>>;
::MyString str1(::MyAllocator<char>("ForStr1"));
::MyString str2(::MyAllocator<char>("ForStr2"));
::MyString str3(::MyAllocator<char>("ForStr3"));
现在我有一个简单的std::vector<MyString>
:
std::vector<::MyString> aVector;
aVector.reserve(1024);
我保留了空格以避免重新分配。
现在我推送前两个字符串:
aVector.push_back(str1);
aVector.push_back(str2);
std::cout << "[0]: " << aVector[0].get_allocator().getType() << "\n"
<< "[1]: " << aVector[1].get_allocator().getType() << "\n";
// As expected, it prints:
// [0]: ForStr1
// [1]: ForStr2
印刷的结果是我所期待的。我假设分配器由std::string
容器拥有。
然而如果我用以下方法强制进行一些复制/移动(重新排列):
aVector.insert(aVector.begin(), str3);
// Now we have vector be like:
// [str3:ForStr3] [str1:ForStr1] [str2:ForStr2]
然后,与向量内的字符串关联的分配器似乎已损坏:
const auto& type0 = aVector[0].get_allocator().getType();
const auto& type1 = aVector[1].get_allocator().getType();
const auto& type2 = aVector[2].get_allocator().getType();
std::cout << "[0]: " << type0 << "\n"
<< "[1]: " << type1 << "\n"
<< "[2]: " << type2 << "\n";
打印:
[0]: ForStr1
[1]: ForStr2
[2]: ForStr2
我期待:
[0]: ForStr3
[1]: ForStr1
[2]: ForStr2
为什么会这样?我错过了 UB 吗?
与std::string
相关联的分配器是对象本身的一部分,不是吗?