C++ 用于创建向量中元素的智能参照的设计模式
因为向量中的引用指向内存的位置,而不是抽象元素,所以在更改向量的内存时可能会导致一些问题C++ 用于创建向量中元素的智能参照的设计模式,c++,vector,C++,Vector,因为向量中的引用指向内存的位置,而不是抽象元素,所以在更改向量的内存时可能会导致一些问题 如果引用指向向量中的某个元素,然后该元素被无序移动到向量中的另一个点,则引用不会跟踪该元素,并且在无序移动后将指向不正确的数据 如果元素无效,如果在元素无效之前声明了引用,则仍然可以访问该元素的内容,而无需进行任何安全检查 如果向量调整大小,则所有当前引用都可能无效 我编写了一个示例程序来演示这三个问题 #include <iostream> #include <vector> s
#include <iostream>
#include <vector>
struct entity { //Simple struct of data.
bool alive;
float data;
};
class manager {
std::vector<entity> vec;
size_t count; // Amount of currently alive entities
public:
//Reserves initial_amount of entities, all set to dead, count set to 0.
manager(size_t initial_amount) : vec(initial_amount, { false, 0.0f }), count(0) {}
entity& create(float f) {
vec[count] = {true, f};
return vec[count++];
}
void refresh() { //Two iterators, one starts at the front of the vector, the other at
size_t front = 0; //count. The front iterator searches for dead entities and swaps them
size_t back = count; //with alive entities from the back iterator. For each swap we decrement
//count by 1, with the final result being all alive entities are between
while(true) { //0 and count.
for( ; true; ++front) {
if (front > back) return;
if (!vec[front].alive) break;
}
for( ; true; --back) {
if (vec[back].alive) break;
if (back <= front) return;
}
std::swap(vec[back], vec[front]);
--count;
++front;
--back;
}
}
void grow(size_t n) {
vec.resize(n);
}
void print() { //Prints all alive entities.
for (size_t index = 0; index < count; index++)
std::cout << vec[index].data << " ";
std::cout << std::endl;
}
};
int main() {
using namespace std;
manager c(10);
entity& d1 = c.create(5.5);
entity& d2 = c.create(10.5);
entity& d3 = c.create(7.5);
// Correct behavior
cout << d1.data << endl; // 5.5
cout << d2.data << endl; // 10.5
cout << d3.data << endl; // 7.5
cout << endl;
d2.alive = false; // "Kill" the entity
c.refresh(); // removes all dead entities. (this will swap d2's and d3's data in the vector,
// but wont change the locations they point to)
// Oh no! d2 and d3 still point to the same locations in the vector and now their data
// is incorrect after the swap, also d2 is dead maybe that should just be an error.
cout << d1.data << endl; // 5.5
cout << d2.data << endl; // 7.5
cout << d3.data << endl; // 10.5
cout << endl;
c.print(); // Correct behavior, prints only alive entities.
cout << endl;
d3.data = 6.5; // Trying to change the value of d3, which should still be alive.
c.print(); // Error, because d3 still points to the 3rd slot the intended value hasn't been changed.
cout << endl;
c.grow(10000);
cout << d1.data << endl; // After resize all these references are invalidated,
cout << d2.data << endl; // and using them is undefined behavior.
cout << d3.data << endl;
return 0;
}
#包括
#包括
结构实体{//数据的简单结构。
布尔活着;
浮动数据;
};
班级经理{
std::vec;
size\u t count;//当前活动实体的数量
公众:
//保留实体的初始数量,所有设置为“死”,计数设置为0。
管理器(大小和初始金额):vec(初始金额,{false,0.0f}),count(0){}
实体和创建(浮动f){
vec[count]={true,f};
返回向量[count++];
}
void refresh(){//两个迭代器,一个从向量的前面开始,另一个从
size\u t front=0;//count。前端迭代器搜索死实体并交换它们
size\u t back=count;//使用来自back迭代器的活动实体。对于每个交换,我们递减
//按1计数,最终结果是所有活动实体介于
while(true){//0并计数。
for(;true;++front){
如果(前>后)返回;
如果(!vec[front].alive)中断;
}
for(;true;--back){
如果(vec[back].alive)中断;
如果(返回使用std::vector
,您可以获得所需的安全性:
class manager {
std::vector<std::shared_ptr<entity>> vec;
public:
//Reserves initial_amount of entities
explicit manager(size_t initial_amount) { vec.reserve(initial_amount); }
std::weak_ptr<entity> create(float f) {
vec.push_back(std::make_unique<entity>(entity{true, f}));
return vec.back();
}
void refresh() {
vec.erase(std::remove_if(vec.begin(), vec.end(),
[](const auto& ent) {return !ent->alive;}),
vec.end());
}
void grow(size_t n) { vec.reserve(n); }
void print() { //Prints all alive entities.
for (const auto& ent : vec)
std::cout << ent->data << " ";
std::cout << std::endl;
}
};
类管理器{
std::vec;
公众:
//储备实体的初始金额
显式管理器(大小初始金额){vec.reserve(初始金额);}
标准::弱ptr创建(浮点f){
vec.push_back(std::make_unique(entity{true,f}));
返回vec.back();
}
无效刷新(){
向量擦除(std::remove_if(vec.begin(),vec.end(),
[](const auto&ent){return!ent->alive;}),
vec.end());
}
空增长(大小n){vec.reserve(n);}
void print(){//打印所有活动实体。
用于(常数自动和输入:vec)
std::在一个单词中输入数据,不。但是你可以有一个指针向量。
int main() {
manager c(10);
auto d1 = c.create(5.5);
auto d2 = c.create(10.5);
auto d3 = c.create(7.5);
// Correct behavior
if (auto e = d1.lock()) std::cout << e->data << std::endl; else std::cout << "Die\n"; // 5.5
if (auto e = d2.lock()) std::cout << e->data << std::endl; else std::cout << "Die\n"; // 10.5
if (auto e = d3.lock()) std::cout << e->data << std::endl; else std::cout << "Die\n"; // 7.5
std::cout << std::endl;
if (auto e = d2.lock()) e->alive = false; // "Kill" the entity
c.refresh(); // removes all dead entities.
if (auto e = d1.lock()) std::cout << e->data << std::endl; else std::cout << "Die\n"; // 5.5
if (auto e = d2.lock()) std::cout << e->data << std::endl; else std::cout << "Die\n"; // Die
if (auto e = d3.lock()) std::cout << e->data << std::endl; else std::cout << "Die\n"; // 10.5
std::cout << std::endl;
c.print(); // Correct behavior, prints only alive entities.
std::cout << std::endl;
if (auto e = d3.lock()) e->data = 6.5; // Trying to change the value of d3,
// which should still be alive.
c.print();
std::cout << std::endl;
c.grow(10000);
if (auto e = d1.lock()) std::cout << e->data << std::endl; else std::cout << "Die\n"; // 5.5
if (auto e = d2.lock()) std::cout << e->data << std::endl; else std::cout << "Die\n"; // Die
if (auto e = d3.lock()) std::cout << e->data << std::endl; else std::cout << "Die\n"; // 6.5
}