如何使指针/引用的元素在向量上
How to make pointer/reference on element in vector?
我有两个向量,对于一些元素(不是全部)我需要它们连接~如果我在一个向量中删除/更改这个元素,它应该在两个向量中删除/更改。
类似于指针:
int r = 10;
int *p= &r;
*p = 3;
例如在下一个代码中,它应该改变myvector2[0]。A到7.
#include <iostream>
#include <vector>
using namespace std;
struct elt {
int a, b, c;
};
int main()
{
vector<elt> myvector;
vector <elt> myvector2;
elt elt1 = {1,3,3};
myvector.push_back(elt1);
elt *elt2 = &elt1;
myvector2.push_back(*elt2);
myvector[0].a=7;
cout << myvector[0].a << endl; //7
cout << myvector2[0].a << endl; //1
return 0;
}
我怎样才能使这成为可能?请帮助! !
正如tgmath所解释的,问题是在vector中最终会有两个不同的对象,因为标准容器是按值存储元素的。我建议您使用共享指针来适当地维护对象的生命周期(注意这使用了c++ 11的特性):
#include <iostream>
#include <vector>
#include <memory>
struct elt {
int a, b, c;
};
int main()
{
std::vector<std::shared_ptr<elt>> myvector;
std::vector<std::shared_ptr<elt>> myvector2;
auto elt1 = std::make_shared<elt>(elt {1,3,3});
myvector.push_back(elt1);
myvector2.push_back(elt1);
myvector[0]->a=7;
std::cout << myvector[0]->a << std::endl; //7
std::cout << myvector2[0]->a << std::endl; //7
return 0;
}
指向std::vector
元素的指针和引用(以及迭代器)在向量重新分配时失效,这可能发生在插入过程中。因此,只有在保证向量在指针/引用的生命周期内不会重新分配时,才能保留这些值。如果不插入vector,或者在开始之前(在获取指针/引用/迭代器之前)对vector调用reserve()
,扩展vector的容量,这样就不需要重新分配空间。
如果你不能保证这一点,你唯一的选择是保留索引而不是指针/引用。当然,你还需要访问vector本身来实现这一点,但是你应该能够保留一个指向它的指针或引用,例如
typedef std::pair<std::vector<elt>*, size_t> ReferenceIntoVector;
myvector2.push_back(*elt2);
将*elt2
的副本添加到myvector2
这意味着两个向量都有自己的elt
对象副本。它们都不同于elt1
。
如果你改变了第一个向量中的一个,第二个向量根本不改变。为此,您需要std::vector<elt*>
在不同的向量中具有指向同一对象的不同指针。
首先,如果碰巧从另一个vector中删除了一个元素,则没有内置的方法自动将其从一个vector中删除。
在我看来,这里有两种不同的挑战:
- 如何更新一个列表所指向的元素,使其在另一个列表中更新?
- 如何从一个列表中删除元素,并从另一个列表中删除该元素?
第一个问题已经在其他帖子中得到了回答:使用std::共享指针而不是本地指针。它们同样快,并且会为你处理所有的内存管理。
请注意:这种方法只在您只更改共享指针所指向的元素的值时才有效,而不是共享指针所指向的。
换句话说/代码:
std::vector<std::shared_ptr<elt>> vec1, vec2;
// Insert some elements
vec1.push_back( std::make_shared( elt{ 1, 2, 3} );
vec2.push_back( vec1.back() );
vec1[0]->x = 5; // OK, updated in both vectors.
vec1[0] = make_shared(elt {3,2,1}); // Error: vec1[0] is pointing to a new object.
另一个挑战要困难得多,如何从两个向量中自动删除元素。简短的回答是"你不能",长一点的回答是"你可以但不能直接"。
方法1:设置已删除的元素为nullptr
.
这种方法有点脏,我不推荐这种方法,因为它需要所有使用vector的代码来检查元素是否为nullptr
。
// Encapsulate the object inside a `std::unique_ptr`
std::vector< std::shared_ptr< std::unique_ptr< elt >>> vec1, vec2;
// Adding elements are done similarly as before
vec1.push_back( std::make_shared( std::make_unique( elt{ 1, 2, 3} )));
vec2.push_back( vec1.back() );
// Now to delete a element you would do as follows
vec1[0]->reset(nullptr); // Flag this element as deleted
vec1[0]->erase( vec1.begin() ); // Remove element from vec1
// Now let us assume we are iterating through the other vector at a later time:
for (auto it = vec2.begin(); it != vec2.end(); ++it ) { // Using iterators makes the code cleaner.
if ( **it == nullptr ) { // If the unique_ptr == nullptr
it = erase(it);
else {
etl & the_value = ***it; // Yes you need all three, one for the iterator, one for the shared_ptr and one for the unique_ptr...
}
}
正如你所看到的,这很快就变得复杂了。但如果这就是你所需要的,它可以工作。
方法2:(在我看来更好)是使用观察者/观察设计模式。
为了实现此模式,您需要将vector转换为另一个类。让我们举一个简单的例子:
// First, create an interface describing all operations you want to be
// informed about.
template<class T>
class SharedElementListObserver {
protected:
void elementDeleted( const shared_ptr<T> & elem ) = 0;
}
template<class T>
class SharedElementList : public SharedElementListObserver<T> {
std::vector<std::shared_ptr<T>> data;
std::unordered_set<SharedElementListObserver*> observers;
public:
void push_back( const T & elem ) { data.push_back( std::make_shared<T>( elem )); }
void push_back( std::shared_ptr &sptr ) { data.push_back( sptr ); }
shared_ptr<T> operator[] (int index) {
return data[index];
}
shared_ptr<const T> operator[] (int index ) const {
return std::static_pointer_cast<const T>( data[index] );
}
// This will cause all instances of elem in all lists
// linked either directly and indirectly to this
// to be removed.
void delete( int idx ) {
if (idx >= 0 && idx < data.size() ) {
shared_ptr<T> temp = data[idx];
data.erase( data.begin() + idx );
for (auto observer : observers) {
observer->elementDeleted(temp);
}
}
}
// Link another list to this one to listen to deletions.
void link( SharedElementListObserver* observer ) {
if (observer == this) return;
else if (observers.insert(observer).second) {
observer->observers.insert(this);
}
}
// Unlink previously linked observer.
void unlink(SharedElementListObserver* observer) {
observer->observers.erase(this);
this->observers.erase(observer);
}
protected:
void elementDeleted( shared_ptr<T> & elem ) {
for (int i = 0; i < data.size(); ) {
if (data[i] == elem)
delete(i); // Not infinite loop, because of test above.
else
i++;
}
}
// You also need to write an operator=, a copy-constructor and a destructor
// that ensures that there are no dead observers in the observers list.
};
根据你的假设,这个类可以用许多不同的方式实现。有些可能比我刚才做的更简单。
以上代码如有错误,请告知。
- 向量元素的引用地址与它所指向的向量元素的地址不同.为什么
- C++:如何循环通过向量中的整数元素
- 如何在C++向量中奇数元素前面加上值-1,我在使用insert函数时遇到了问题
- 不允许在向量中添加更多元素
- 基于范围的 for 循环:迭代使用一个元素扩展的向量
- 使用并行参数向量调用元素向量的成员函数
- C++ 查找字符串中存在的元素向量
- 包含 std::threads 的元素向量
- 避免从单一元素向量转换为基元类型
- 对自定义元素向量进行排序时出现意外(至少对我来说)行为
- 如何为对元素(向量和int)配对创建unique_ptr也是unique_ptr
- 元素向量乘法 C++(代码不起作用)
- 时间和空间复杂性在二叉树的每个级别创建元素向量(NON-BST)
- 遍历结构元素向量
- 犰狳C++中的元素向量或矩阵乘法
- 为什么'std::vector<int> b{2};'创建 1 元素向量,而不是 2 元素向量?
- 可移动元素向量的大小调整是否有效?
- 唯一元素向量的c++模板函数
- 获取索引和元素-向量问题
- 定义一个生成元素向量的函数时,正确的方法是什么?