对我来说这是一个学习问题,希望其他人也是如此。我的问题分解为指针指向向量的内容。当我擦除向量的第一个元素时会出现问题。我不太确定我在期待什么,我不知何故假设,当移除项目时,矢量不会开始在内存中移动对象。
我的问题是:有没有办法将对象保留在内存中?例如,更改向量的基础容器?在我的特定示例中,我将删除指针访问,并且只使用对象的id,因为类无论如何都需要ID。
这是一个简化的例子:
#include <iostream>
#include <vector>
class A
{
public:
A(unsigned int id) : id(id) {};
unsigned int id;
};
int main()
{
std::vector<A> aList;
aList.push_back(A(1));
aList.push_back(A(2));
A * ptr1 = &aList[0];
A * ptr2 = &aList[1];
aList.erase(aList.begin());
std::cout << "Pointer 1 points to \t" << ptr1 << " with content " << ptr1->id << std::endl;
std::cout << "Pointer 2 points to \t" << ptr2 << " with content " << ptr2->id << std::endl;
std::cout << "Element 1 is stored at \t" << &aList[0] << " with content " << aList[0].id << std::endl;
}
我得到的是:
Pointer 1 points to 0xf69320 with content 2
Pointer 2 points to 0xf69324 with content 2
Element 1 is stored at 0xf69320 with content 2
答案 0 :(得分:1)
虽然你无法达到你想要的目的,但有两种简单的选择。第一种方法是使用std::vector<std::unique_ptr<T>>
代替std::vector<T>
。向量调整大小时,不会移动每个对象的实际实例。这意味着将&aList[i]
使用aList[i].get()
和aList[i].id
更改为aList[i]->id
。
#include <iostream>
#include <memory>
#include <vector>
class A
{
public:
A(unsigned int id) : id(id) {};
unsigned int id;
};
int main()
{
std::vector<std::unique_ptr<A>> aList;
aList.push_back(std::make_unique<A>(1));
aList.push_back(std::make_unique<A>(2));
A * ptr1 = aList[0].get();
A * ptr2 = aList[1].get();
aList.erase(aList.begin());
// This output is undefined behavior, ptr1 points to a deleted object
//std::cout << "Pointer 1 points to \t" << ptr1 << " with content " << ptr1->id << std::endl;
std::cout << "Pointer 2 points to \t" << ptr2 << " with content " << ptr2->id << std::endl;
std::cout << "Element 1 is stored at \t" << aList[0].get() << " with content " << aList[0]->id << std::endl;
}
请注意,ptr1
将指向一个已删除的对象,因此它仍然是未定义的行为以使其顺从。
另一种解决方案可能是使用不会使引用和指针无效的其他容器。 std::list
永远不会使节点无效,除非它被特别删除。但是,不支持随机访问,因此无法直接修改您的示例以使用std::list
。您必须遍历列表才能获得指针。
答案 1 :(得分:0)
不确定这是否是您想要的,但是如何:
(只有基本布局,你需要填写细节,还有:避免测试设计,可能会有一些缺陷)
template <class T>
class MagicVector {
class MagicPointer {
friend class MagicVector;
private:
MagicVector* parent;
unsigned int position;
bool valid;
MagicPointer(MagicVector* par, const unsigned int pos); //yes, private!
public:
~MagicPointer();
T& content();
void handle_erase(const unsigned int erase_position);
}
friend class MagicPointer;
private:
vector<T> data;
vector<std::shared_ptr<MagicPointer> > associated_pointers;
public:
(all the methods you need from vector)
void erase(const unsigned int position);
std::shared_ptr<MagicPointer> create_pointer(const unsigned int position);
}
template <class T>
void MagicVector<T>::erase(const unsigned int position){
data.erase(position);
for(unsigned int i=0; i<associated_pointers.size(); i++){
associated_pointers[i].handle_erase(position);
}
}
template <class T>
std::shared_ptr<MagicPointer> MagicVector<T>::create_pointer(const unsigned int position){
associated_pointers.push_back(std::shared_ptr<MagicPointer>(new MagicPointer(this, position)));
return std::shared_ptr<MagicPointer>(associated_pointers.back());
}
template <class T>
MagicVector<T>::MagicPointer(MagicVector* par, const unsigned int pos){
parent = par;
position = pos;
if (position < parent->data.size()){
valid = true;
}else{
valid = false;
}
}
template <class T>
T& MagicVector<T>::MagicPointer::content(){
if(not valid){
(handle this somehow)
}
return parent->data[position];
}
template <class T>
void MagicVector<T>::MagicPointer::handle_erase(const unsigned int erase_position){
if (erase_position < position){
position--;
}
else if (erase_position == position){
valid = false;
}
}
template <class T>
MagicVector<T>::MagicPointer::~MagicPointer(){
for(unsigned int i=0; i<parent->associated_pointers.size(); i++){
if(parent->associated_pointers[i] == this){
parent->associated_pointers.erase(i);
i=parent->associated_pointers.size();
}
}
}
基本思想:你有自己的矢量和指针类,指针在矢量中存储一个位置。向量知道它的指针,并在擦除某些东西时相应地处理它们。
我自己并不完全满意,MagicPointer上的shared_ptr看起来很难看,但不知道如何简化这一点。也许我们需要使用三个类,MagicVector,存储父级和位置的MagicPointerCore以及MagicPointer:public shared_ptr&lt; MagicPointerCore&gt;,MagicVector具有向量&lt; MagicPointerCore&GT; associated_pointers。
请注意,MagicVector的析构函数必须将其所有关联指针设置为无效,因为MagicPointer可以比其父级的范围更长。
答案 2 :(得分:-1)
我在期待,我以某种方式假设,在删除项目时,矢量不会开始在内存中移动对象。
怎么样?你还期待什么? std::vector
保证内存中包含连续元素的连续序列。因此,如果删除某些内容,则需要在该连续内存中替换其他元素。