C++ 在这种情况下,在c+中是否可以避免手动管理内存+;?
我有一个C++ 在这种情况下,在c+中是否可以避免手动管理内存+;?,c++,pointers,memory-management,reference,C++,Pointers,Memory Management,Reference,我有一个存储类,它保存了事物的列表: #include <iostream> #include <list> #include <functional> class Thing { private: int id; int value = 0; static int nextId; public: Thing() { this->id = Thing::nextId++;
存储
类,它保存了事物的列表
:
#include <iostream>
#include <list>
#include <functional>
class Thing {
private:
int id;
int value = 0;
static int nextId;
public:
Thing() { this->id = Thing::nextId++; };
int getId() const { return this->id; };
int getValue() const { return this->value; };
void add(int n) { this->value += n; };
};
int Thing::nextId = 1;
class Storage {
private:
std::list<std::reference_wrapper<Thing>> list;
public:
void add(Thing& thing) {
this->list.push_back(thing);
}
Thing& findById(int id) const {
for (std::list<std::reference_wrapper<Thing>>::const_iterator it = this->list.begin(); it != this->list.end(); ++it) {
if (it->get().getId() == id) return *it;
}
std::cout << "Not found!!\n";
exit(1);
}
};
我的main()
只需调用run()
。我得到的结果是:
50
10101
Not found!!
尽管我在寻找:
50
10101
50
问题 函数返回时,本地声明的对象t4似乎不再存在,这很有意义。我可以通过使用
new
动态分配内存来防止这种情况,但我不想手动管理内存
如何在不删除temp()
函数和不必手动管理内存的情况下修复代码?
如果我只是像一些人建议的那样使用
std::list
,那么t4
和temp
的问题肯定将不再存在,但会出现另一个问题:例如,代码将不再打印10101
。如果我一直复制内容,我将无法更改存储对象的状态。谁是存储中对象的所有者?
你真正的问题是所有权。目前,您的存储
实际上并不包含内容
,而是由存储
的用户来管理放入其中的对象的生存期。这与std容器的理念大相径庭。所有对象都拥有您放入其中的对象,容器管理它们的生存期(例如,您只需调用一个向量,最后两个元素就会被销毁)
为什么要引用?
您已经找到了一种使容器不拥有实际对象的方法(通过使用reference\u wrapper
),但是没有理由这样做。对于一个名为Storage
的类,我希望它能够保存对象,而不仅仅是引用。此外,这为许多令人讨厌的问题打开了大门,包括未定义的行为。例如:
void temp(Storage& storage) {
storage.findById(2).add(1);
Thing t4; t4.add(50);
storage.add(t4);
std::cout << storage.findById(4).getValue() << "\n";
}
然后
要使用存储
执行此操作,只需使findById
返回一个引用即可。作为演示:
struct foo {
private:
int data;
public:
int& get_ref() { return data;}
const int& get_ref() const { return data;}
};
auto x = foo();
x.get_ref = 12;
TL;DR
如何避免人工资源管理?让其他人帮你做,并称之为自动资源管理:P
谁是存储中物品的所有者?
你真正的问题是所有权。目前,您的存储
实际上并不包含内容
,而是由存储
的用户来管理放入其中的对象的生存期。这与std容器的理念大相径庭。所有对象都拥有您放入其中的对象,容器管理它们的生存期(例如,您只需调用一个向量,最后两个元素就会被销毁)
为什么要引用?
您已经找到了一种使容器不拥有实际对象的方法(通过使用reference\u wrapper
),但是没有理由这样做。对于一个名为Storage
的类,我希望它能够保存对象,而不仅仅是引用。此外,这为许多令人讨厌的问题打开了大门,包括未定义的行为。例如:
void temp(Storage& storage) {
storage.findById(2).add(1);
Thing t4; t4.add(50);
storage.add(t4);
std::cout << storage.findById(4).getValue() << "\n";
}
然后
要使用存储
执行此操作,只需使findById
返回一个引用即可。作为演示:
struct foo {
private:
int data;
public:
int& get_ref() { return data;}
const int& get_ref() const { return data;}
};
auto x = foo();
x.get_ref = 12;
TL;DR
如何避免人工资源管理?让其他人帮你做这件事,并称之为自动资源管理:P
t4
是一个临时对象,在退出temp()
时被销毁,而你存储在存储中的内容将成为一个悬空引用,导致UB
不太清楚您想要实现什么,但是如果您想保持存储
类不变,那么应该确保存储在其中的所有引用至少与存储
本身一样长。您已经发现这是STL容器保留其元素的私有副本的原因之一(其他原因可能不那么重要,因为在某些情况下消除了额外的间接性和更好的局部性)
另外,请停止编写这些this->
并了解构造函数中的初始化列表,好吗?>_ t4
是一个临时对象,它在退出temp()
时被销毁,您存储在存储器中的内容将成为一个悬空引用,导致UB
不太清楚您想要实现什么,但是如果您想保持存储
类不变,那么应该确保存储在其中的所有引用至少与存储
本身一样长。您已经发现这是STL容器保留其元素的私有副本的原因之一(其他原因可能不那么重要,因为在某些情况下消除了额外的间接性和更好的局部性)
另外,请停止编写这些this->
并了解构造函数中的初始化列表,好吗?>_ 根据我的估计,就您的代码实际执行的功能而言,您的代码显然过于复杂了。考虑这个代码,它做所有与你的代码相同的事情,但是用更少的样板代码和一种对你的使用来说更安全的方式:
#include<map>
#include<iostream>
int main() {
std::map<int, int> things;
int & t1 = things[1];
int & t2 = things[2];
int & t3 = things[3];
t1 = 10;
t2 = 100;
t3 = 1000;
t2++;
things[4] = 50;
std::cout << things.at(4) << std::endl;
t2 += 10000;
std::cout << things.at(2) << std::endl;
std::cout << things.at(4) << std::endl;
things.at(2) -= 75;
std::cout << things.at(2) << std::endl;
std::cout << t2 << std::endl;
}
//Output:
50
10101
50
10026
10026
这些代码片段应该让您对语言的工作原理有一个很好的了解,以及您需要了解哪些原则,这些原则可能是我编写的代码中不熟悉的。我的一般建议是找到一个好的C++资源来学习语言的基础知识,并从中学习。一些好的资源
最后一件事:如果使用<代码>东西>代码对代码非常重要,因为您需要在地图中保存更多的数据,请考虑这一点:
#include<map>
#include<iostream>
#include<string>
//Only difference between struct and class is struct sets everything public by default
struct Thing {
int value;
double rate;
std::string name;
Thing() : Thing(0,0,"") {}
Thing(int value, double rate, std::string name) : value(value), rate(rate), name(std::move(name)) {}
};
int main() {
std::map<int, Thing> things;
Thing & t1 = things[1];
t1.value = 10;
t1.rate = 5.7;
t1.name = "First Object";
Thing & t2 = things[2];
t2.value = 15;
t2.rate = 17.99999;
t2.name = "Second Object";
t2.value++;
std::cout << things.at(2).value << std::endl;
t1.rate *= things.at(2).rate;
std::cout << things.at(1).rate << std::endl;
std::cout << t1.name << "," << things.at(2).name << std::endl;
things.at(1).rate -= 17;
std::cout << t1.rate << std::endl;
}
#包括
#包括
#包括
//struct和class之间的唯一区别是默认情况下struct将所有内容都设置为公共
结构物{
int值;
双倍费率;
std::字符串名;
Thing():Thing(0,0
#include<map>
#include<iostream>
int main() {
std::map<int, int> things;
int & t1 = things[1];
int & t2 = things[2];
int & t3 = things[3];
t1 = 10;
t2 = 100;
t3 = 1000;
t2++;
things[4] = 50;
std::cout << things.at(4) << std::endl;
t2 += 10000;
std::cout << things.at(2) << std::endl;
std::cout << things.at(4) << std::endl;
things.at(2) -= 75;
std::cout << things.at(2) << std::endl;
std::cout << t2 << std::endl;
}
//Output:
50
10101
50
10026
10026
#include<map>
#include<iostream>
int & insert(std::map<int, int> & things, int value) {
static int id = 1;
int & ret = things[id++] = value;
return ret;
}
int main() {
std::map<int, int> things;
int & t1 = insert(things, 10);
int & t2 = insert(things, 100);
int & t3 = insert(things, 1000);
t2++;
insert(things, 50);
std::cout << things.at(4) << std::endl;
t2 += 10000;
std::cout << things.at(2) << std::endl;
std::cout << things.at(4) << std::endl;
things.at(2) -= 75;
std::cout << things.at(2) << std::endl;
std::cout << t2 << std::endl;
}
//Output:
50
10101
50
10026
10026
#include<map>
#include<iostream>
#include<string>
//Only difference between struct and class is struct sets everything public by default
struct Thing {
int value;
double rate;
std::string name;
Thing() : Thing(0,0,"") {}
Thing(int value, double rate, std::string name) : value(value), rate(rate), name(std::move(name)) {}
};
int main() {
std::map<int, Thing> things;
Thing & t1 = things[1];
t1.value = 10;
t1.rate = 5.7;
t1.name = "First Object";
Thing & t2 = things[2];
t2.value = 15;
t2.rate = 17.99999;
t2.name = "Second Object";
t2.value++;
std::cout << things.at(2).value << std::endl;
t1.rate *= things.at(2).rate;
std::cout << things.at(1).rate << std::endl;
std::cout << t1.name << "," << things.at(2).name << std::endl;
things.at(1).rate -= 17;
std::cout << t1.rate << std::endl;
}
#include <iostream>
#include <list>
#include <memory>
class Thing {
private:
int id;
int value = 0;
static int nextId;
public:
Thing() { this->id = Thing::nextId++; };
int getId() const { return this->id; };
int getValue() const { return this->value; };
void add(int n) { this->value += n; };
};
int Thing::nextId = 1;
class Storage {
private:
std::list<std::shared_ptr<Thing>> list;
public:
void add(const std::shared_ptr<Thing>& thing) {
this->list.push_back(thing);
}
std::shared_ptr<Thing> findById(int id) const {
for (std::list<std::shared_ptr<Thing>>::const_iterator it = this->list.begin(); it != this->list.end(); ++it) {
if (it->get()->getId() == id) return *it;
}
std::cout << "Not found!!\n";
exit(1);
}
};
void add_another(Storage& storage) {
storage.findById(2)->add(1);
std::shared_ptr<Thing> t4 = std::make_shared<Thing> (); t4->add(50);
storage.add(t4);
std::cout << storage.findById(4)->getValue() << "\n";
}
int main() {
std::shared_ptr<Thing> t1 = std::make_shared<Thing> (); t1->add(10);
std::shared_ptr<Thing> t2 = std::make_shared<Thing> (); t2->add(100);
std::shared_ptr<Thing> t3 = std::make_shared<Thing> (); t3->add(1000);
Storage storage;
storage.add(t3);
storage.add(t1);
storage.add(t2);
add_another(storage);
t2->add(10000);
std::cout << storage.findById(2)->getValue() << "\n";
std::cout << storage.findById(4)->getValue() << "\n";
return 0;
}
50
10101
50
class Storage {
private:
std::list<Thing*> list;
public:
void add(Thing& thing) {
this->list.push_back(&thing);
}
Thing* findById(int id) const {
for (auto thing : this->list) {
if (thing->getId() == id) return thing;
}
std::cout << "Not found!!\n";
return nullptr;
}
};