C++ 防止移动向量项

C++ 防止移动向量项,c++,pointers,vector,erase,C++,Pointers,Vector,Erase,这对我来说是一个学习问题,希望其他人也能这样。我的问题是让指针指向向量的内容。当我擦除向量的第一个元素时,就会出现问题。我不太确定我期望的是什么,我不知怎么地假设,当删除项时,向量不会开始移动内存中的对象 我的问题是:有没有一种方法可以将这些对象保存在内存中?例如,更改vector的底层容器?在我的特定示例中,我将删除指针访问,只使用对象的和id,因为该类无论如何都需要id 以下是一个简化的示例: #包括 #包括 甲级 { 公众: A(无符号整数id):id(id){}; 无符号整数id; };

这对我来说是一个学习问题,希望其他人也能这样。我的问题是让指针指向向量的内容。当我擦除向量的第一个元素时,就会出现问题。我不太确定我期望的是什么,我不知怎么地假设,当删除项时,向量不会开始移动内存中的对象

我的问题是:有没有一种方法可以将这些对象保存在内存中?例如,更改vector的底层容器?在我的特定示例中,我将删除指针访问,只使用对象的和id,因为该类无论如何都需要id

以下是一个简化的示例:

#包括
#包括
甲级
{
公众:
A(无符号整数id):id(id){};
无符号整数id;
};
int main()
{
std::向量表;
A.推回(A(1));
A.推回(A(2));
A*ptr1=&aList[0];
A*ptr2=&aList[1];
aList.erase(aList.begin());
标准::cout
我以为,我不知怎么地假设,当删除项时,向量不会开始移动内存中的对象


怎么会这样?你还期望什么?一个
std::vector保证它在内存中包含一系列连续的元素。因此,如果某个元素被删除,其他元素需要在该连续内存中被替换。

虽然你不能准确地实现你想要的,但有两个简单的选择。第一个是使用
std::vect或者
而不是
std::vector
。当向量调整大小时,每个对象的实际实例不会移动。这意味着将
&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;

}
#包括
#包括
#包括
甲级
{
公众:
A(无符号整数id):id(id){};
无符号整数id;
};
int main()
{
std::向量表;
列表。推回(std::make_unique(1));
列表。推回(std::make_unique(2));
A*ptr1=aList[0].get();
A*ptr2=aList[1].get();
aList.erase(aList.begin());
//此输出是未定义的行为,ptr1指向已删除的对象

//std::cout不确定这是否是您想要的,但是这个怎么样:

(只有基本布局,你需要填写细节,还有:没有测试过设计,可能有一些缺陷)

模板
类MagicVector{
类磁指向器{
朋友级MagicVector;
私人:
MagicVector*家长;
无符号整数位置;
布尔有效;
MagicPointer(MigcVix*Par,const un签署int POS);//是的,私有的!
公众:
~MagicPointer();
T&content();
无效句柄擦除(常量无符号整数擦除位置);
}
朋友级魔术师;
私人:
矢量数据;
向量相关_指针;
公众:
(从vector获得您需要的所有方法)
无效擦除(常量无符号整数位置);
std::shared_ptr create_指针(const unsigned int position);
}
模板
无效MagicVector::擦除(常量无符号整数位置){
数据删除(位置);
for(无符号整数i=0;idata.size()){
有效=真;
}否则{
有效=错误;
}
}
模板
T&MagicVector::MagicPointer::content(){
如果(无效){
(以某种方式处理)
}
返回父项->数据[位置];
}
模板
void MagicVector::MagicPointer::handle_erase(常量无符号整数擦除位置){
如果(擦除位置<位置){
位置--;
}
else if(擦除位置==位置){
有效=错误;
}
}
模板
MagicVector::MagicPointer::~MagicPointer(){
for(unsigned int i=0;IASociated_pointers.size();i++){
if(父级->关联的_指针[i]==此){
父->关联的_指针。擦除(i);
i=父->关联的_指针.size();
}
}
}
基本思想:你有自己的向量和指针类,指针在向量中存储一个位置。向量知道它是指针,每当有东西被擦除时,它就会相应地处理它们

我自己并不完全满意,MagicPointer上的shared_ptr看起来很难看,但不知道如何简化。也许我们需要使用三个类,MagicVector、MagicPointerCore(存储父对象和位置)和MagicPointer:public shared_ptr,MagicVector关联了vector_指针


请注意,MagicVector的析构函数必须将其所有关联指针设置为无效,因为MagicPointer可能超出其父对象的作用域。

从向量中删除项(以及许多其他操作)可能会在内存中移动内容。如果要避免这种情况,请使用基于节点的容器,如std::list或std::deque。向量元素按定义存储在连续内存中。如果希望容器将元素保留在适当位置,但记住它已从容器中删除,则如果您确实需要ant创建这样的向量,然后使用std::vector::reserve(),它会保留一个空间,这样当您添加一个新的时,它会将元素放入该保留空间,这样就不会发生重新分配。vector只在需要增加时才重新分配size@LorenceHernandez这并不能阻止
擦除
向前移动元素以填补空白。@LorenceHernandez——叫我傻瓜,但我不会使用
储备金()
来破坏向量的用途。在向向量中插入新项之前,您的应用程序现在必须始终检查您是否超出容量。我也想到了这一点。我不知道这是从哪里来的。是否有一个STL对象来组织保留其地址的对象的列表?@通常不可计算
 std::deque
不太好。您需要一个基于节点的容器,如
std::list
@ruhigbauner如果您想继续使用向量,您可以将元素存储在向量中,但可以通过另一个包含
#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;

}
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();
        }
    }
}