我有一个类,它有一个std :: vector成员,用于存储外部类的对象。
class Example {
private:
std::vector<OtherClass> list_of_things_;
}
class OtherClass {
public:
void ChangeName(std::string name);
private:
std::string name_;
}
通过我的代码我想更改存储在这个list_of_things_中的一些OtherClass对象,所以我在Example类中使用了两个函数:
std::vector<OtherClass> RetrieveObjects() {
std::vector<OtherClass> result;
std::vector<OtherClass>::iterator it;
for (it = list_of_things_.begin(); it != list_of_things_.end(); ++it) {
if (some condition is met) {
result.push_back(*it);
}
}
}
然后在Example中的另一个函数中,我将其称为:
std::vector<OtherClass> objs = RetrieveObjects();
std::vector<OtherClass>::iterator it;
for (it = objs.begin(); it != objs.end(); ++it) {
it->ChangeName("new name");
}
现在,这原则上是有效的,但只有当我从objs变量中检查名称时,这才会改变list_of_things_中的对象,这是我的主要目的。
我是否实际上复制了对象而不是在list_of_things_中检索相同的对象?如果是这样,为什么?我犯了其他错误吗?我应该使用指针吗?我是C ++的新手,仍在寻找解决方法。
在这里您可以找到运行的测试代码:
#include <vector>
#include <string>
#include <iostream>
class OtherClass {
public:
OtherClass(std::string s) : name_(s) {}
std::string GetName();
void ChangeName(std::string name);
private:
std::string name_;
};
std::string OtherClass::GetName() {
return name_;
}
void OtherClass::ChangeName(std::string name) {
name_ = name;
}
class Example {
public:
Example(std::vector<OtherClass> l) : list_of_things_(l) {}
void ChangeNames();
void WriteNames();
protected:
std::vector<OtherClass> RetrieveObjects();
private:
std::vector<OtherClass> list_of_things_;
};
std::vector<OtherClass> Example::RetrieveObjects() {
std::vector<OtherClass> result;
std::vector<OtherClass>::iterator it;
for (it = list_of_things_.begin(); it != list_of_things_.end(); ++it) {
if (it->GetName() == "Name") {
result.push_back(*it);
}
}
return result;
}
void Example::ChangeNames() {
std::vector<OtherClass> objs = RetrieveObjects();
std::vector<OtherClass>::iterator it;
for (it = objs.begin(); it != objs.end(); ++it) {
it->ChangeName("new name");
std::cout << it->GetName() << std::endl;
}
}
void Example::WriteNames() {
std::vector<OtherClass>::iterator it;
for (it = list_of_things_.begin(); it != list_of_things_.end(); ++it) {
std::cout << it->GetName() << std::endl;
}
}
int main() {
OtherClass oc = OtherClass("Name");
OtherClass oc2 = OtherClass("None");
OtherClass oc3 = OtherClass("Name");
std::vector<OtherClass> v = {oc, oc2, oc3};
Example ex = Example(v);
ex.ChangeNames();
ex.WriteNames();
}
谢谢!
答案 0 :(得分:3)
您只对本地objs
向量进行了更改,该向量是{em> list_of_things_
向量的副本。由于您从未将副本中的更改写回成员,因此在objs
被销毁时它们会丢失。
解决此问题的最简单方法是不要在RetrieveObjects
内拨打ChangeNames
,而是直接在list_of_things_
成员上工作:
void Example::ChangeNames() {
std::vector<OtherClass>::iterator it;
for (it = list_of_things_.begin(); it != list_of_things_.end(); ++it) {
it->ChangeName("new name");
std::cout << it->GetName() << std::endl;
}
}
您可以在RetrieveObjects
:
std::vector<OtherClass> Example::RetrieveObjects()
此处的返回值是一个新的std::vector<OtherClass>
对象。如果您想要引用现有的类对象,则签名将更改为:
std::vector<OtherClass>& Example::RetrieveObjects()
请注意返回值上的额外&
。这与C#和Java等语言不同,其中某些复杂类型总是通过引用传递。
返回对成员向量的引用的RetrieveObjects
实现将是:
std::vector<OtherClass>& Example::RetrieveObjects() {
return list_of_things_;
}
答案 1 :(得分:0)
已经有人说你修改了矢量的副本,这就是你的主矢量保持不变的原因。 如果使用智能指针而不是简单对象,则可以使用此方法。
typedef std::shared_ptr<OtherClass> OtherClassPtr;
然后将所有OtherClass使用替换为OtherClassPtr以便您拥有 其他的ClassCtr对象的std :: vector,等等。你必须以不同的方式创建它们(std :: make_shared())而不是。你用 - &gt; 但是在你复制几个对象并修改它们之后,它们将被修改,因为你只复制指针。
答案 2 :(得分:0)
我是否实际上复制了对象而不是在list_of_things _中检索相同的对象?
是。您可以创建一个新的矢量,保存原始值的副本,这些副本符合您的选择标准。
如果是这样,为什么?
std::vector<OtherClass> Example::RetrieveObjects() { // returns a new vector
std::vector<OtherClass> result;
std::vector<OtherClass>::iterator it;
for (it = list_of_things_.begin(); it != list_of_things_.end(); ++it) {
if (it->GetName() == "Name") {
result.push_back(*it); // The content of *it is copied to the new element of result.
}
}
return result; // do return a new vector, holding copies of originals
}
void Example::ChangeNames() {
std::vector<OtherClass> objs = RetrieveObjects(); // a local object with auto lifetime
std::vector<OtherClass>::iterator it;
for (it = objs.begin(); it != objs.end(); ++it) {
it->ChangeName("new name"); // acts on local object, class members are intact
std::cout << it->GetName() << std::endl;
}
} // local object is gone with any changes it holds
我是否犯了其他错误?我应该使用指针吗?
我不是先尝试从list_of_things_
进行基于条件的选择,然后对选定的值执行某些操作,而是尝试一次搜索并同时处理原始list_of_things_
。