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