放置到 std::vector 的实例地址无效
Address of an instance emplaced to std::vector is invalid
我有 2 个 std::vector
:
- 第一个向量,我放置实例
- 到第二个vector,我想存储刚刚放置的实例的地址
但是它不起作用,即存储的地址与放置实例的地址不同。
如果这很重要,我会在 Linux 上使用 g++ 5.1 和 clang 3.6 以及 -std=c++11。
这是一个说明问题的工作示例。
#include <iostream>
#include <vector>
struct Foo {
Foo(int a1, int a2) : f1(a1), f2(a2) {}
int f1;
int f2;
};
int main(int, char**) {
std::vector<Foo> vec1;
std::vector<Foo*> vec2;
int num = 10;
for (int i = 0; i < num; ++i) {
vec1.emplace_back(i, i * i);
// I want to store the address of *emplaced* instance...
vec2.push_back(&vec1.back());
}
// same
std::cout << "size 1: " << vec1.size() << std::endl;
std::cout << "size 2: " << vec2.size() << std::endl;
// same for me
std::cout << "back 1: " << &vec1.back() << std::endl;
std::cout << "back 2: " << vec2.back() << std::endl;
// typically differ ?
std::cout << "front 1: " << &vec1.front() << std::endl;
std::cout << "front 2: " << vec2.front() << std::endl;
for (int i = 0; i < num; ++i) {
std::cout << i + 1 << "th" << std::endl;
// same for last several (size % 4) for me
std::cout << "1: " << &vec1[i] << std::endl;
std::cout << "2: " << vec2[i] << std::endl;
}
}
问题
- 这是正确的行为吗?我猜这是由于存储临时实例的地址引起的,但我想知道标准是否允许它(只是好奇)。
- 如果以上为真,如何解决这个问题?我通过将第一个更改为
vector<unique_ptr<Foo>>
来解决这个问题,但是有什么惯用的方法吗?
两个选项:
1) 您可以简单地修复您的测试。您只需要先使用
测试预分配足够的内存
vec1.reserve(10);
嗯,这是 std::vector
的实施细节。随着越来越多的项目被添加到 std::vector
,它需要为它们获得更多的 space。而这个 space 必须是连续的。因此,当 space 不足以容纳新元素时,std::vector
会分配更大的内存块,将现有元素复制到其中,添加新元素,最后释放之前使用的内存块。因此,您存储在 vec2 中的地址可能会变得无效。
但是,如果您为 10 个元素预分配了足够的内存,那么您的代码是正确的。
或者,因为保留内存是一件棘手的事情
2) 使用 std::deque
因为在双端队列的任何一端插入和删除都不会使指向其余元素 (http://en.cppreference.com/w/cpp/container/deque) 的指针或引用无效,并且忘记无效地址的问题。所以不需要预留内存。
我有 2 个 std::vector
:
- 第一个向量,我放置实例
- 到第二个vector,我想存储刚刚放置的实例的地址
但是它不起作用,即存储的地址与放置实例的地址不同。
如果这很重要,我会在 Linux 上使用 g++ 5.1 和 clang 3.6 以及 -std=c++11。
这是一个说明问题的工作示例。
#include <iostream>
#include <vector>
struct Foo {
Foo(int a1, int a2) : f1(a1), f2(a2) {}
int f1;
int f2;
};
int main(int, char**) {
std::vector<Foo> vec1;
std::vector<Foo*> vec2;
int num = 10;
for (int i = 0; i < num; ++i) {
vec1.emplace_back(i, i * i);
// I want to store the address of *emplaced* instance...
vec2.push_back(&vec1.back());
}
// same
std::cout << "size 1: " << vec1.size() << std::endl;
std::cout << "size 2: " << vec2.size() << std::endl;
// same for me
std::cout << "back 1: " << &vec1.back() << std::endl;
std::cout << "back 2: " << vec2.back() << std::endl;
// typically differ ?
std::cout << "front 1: " << &vec1.front() << std::endl;
std::cout << "front 2: " << vec2.front() << std::endl;
for (int i = 0; i < num; ++i) {
std::cout << i + 1 << "th" << std::endl;
// same for last several (size % 4) for me
std::cout << "1: " << &vec1[i] << std::endl;
std::cout << "2: " << vec2[i] << std::endl;
}
}
问题
- 这是正确的行为吗?我猜这是由于存储临时实例的地址引起的,但我想知道标准是否允许它(只是好奇)。
- 如果以上为真,如何解决这个问题?我通过将第一个更改为
vector<unique_ptr<Foo>>
来解决这个问题,但是有什么惯用的方法吗?
两个选项:
1) 您可以简单地修复您的测试。您只需要先使用
测试预分配足够的内存 vec1.reserve(10);
嗯,这是 std::vector
的实施细节。随着越来越多的项目被添加到 std::vector
,它需要为它们获得更多的 space。而这个 space 必须是连续的。因此,当 space 不足以容纳新元素时,std::vector
会分配更大的内存块,将现有元素复制到其中,添加新元素,最后释放之前使用的内存块。因此,您存储在 vec2 中的地址可能会变得无效。
但是,如果您为 10 个元素预分配了足够的内存,那么您的代码是正确的。
或者,因为保留内存是一件棘手的事情
2) 使用 std::deque
因为在双端队列的任何一端插入和删除都不会使指向其余元素 (http://en.cppreference.com/w/cpp/container/deque) 的指针或引用无效,并且忘记无效地址的问题。所以不需要预留内存。