更改标准向量 C++ 中对象的值
Changing values of objects in std vector c++
我注意到我无法更改存储在 std::vector
或 std::map
中的对象的值。在这两种情况下,作为 toggle()
函数调用的结果,下面代码的输出给出了 "0"
。在矢量外部直接使用对象时不存在此行为。我是否缺少有关 std::vector
或类似容器的信息?我们如何正确地将对象存储在容器中并保持更改其值的能力?
#include <iostream>
#include <functional>
#include <vector>
class OtherThing{
public:
void addElement(std::function<int()> func){
this->myfuncs.push_back(func);
}
void toggle(){
std::cout << "toggle .. " << this->myfuncs[0]() << std::endl;
}
private:
std::vector<std::function<int()>> myfuncs;
};
class Thing: public OtherThing{
public:
Thing(){
std::function<int()> myfunc= [this]()->int{
std::cout << "from lambda " << this->value << std::endl;
return this->value;
};
this->addElement(myfunc);
}
void setValue(int value){
this->value = value;
}
int getValue(){
return this->value;
}
private:
int value;
};
int main() {
// container for things
std::vector<Thing> mythings;
// a thing
Thing a;
mythings.push_back(a);
mythings[0].setValue(666);
mythings[0].toggle();
mythings[0].setValue(999);
mythings[0].toggle();
return 0;
}
输出:
clang++-7 -pthread -std=c++17 -o main main.cpp
./main
toggle .. from lambda 0
0
toggle .. from lambda 0
0
push_back(a)
制作 copy a
。 mythings[0]
returns 对该副本的引用。因此,任何修改 mythings[0]
成员的操作都不会反映在 a
中,反之亦然。
然而,当 a
被 push_back()
复制时,Thing
的编译器生成的复制构造函数将按原样复制 myfuncs
向量,因此a
的构造函数存储在该向量中的 lambda 也按原样复制。该 lambda 捕获了指向 a
的 this
指针,而不是新副本。
因此,当您调用 mythings[0].setValue()
时,您正在修改复制的 Thing
的 value
,但是当您调用 mythings[0].toggle()
时,您正在调用一个 lambda打印 a
的 value
- 一开始就没有初始化 ,所以输出是 indeterminate 直到 a.setValue()
被调用。
要解决此问题,您需要为 Thing
实现自己的复制构造函数,它存储自己的 lambda 捕获复制的 Thing
的 this
指针,而不是存储的副本来自 Thing
的早期 lambda 被复制自,例如:
Thing(const Thing &src){
value = src.value;
std::function<int()> myfunc = [this]()->int{
std::cout << "from copied lambda " << this->value << std::endl;
return this->value;
};
this->addElement(myfunc);
}
我也是根据评论尝试的。老实说,我不喜欢这样。太多的脚本只是为了调用 toggle()
#include <iostream>
#include <functional>
#include <vector>
class Thing;
class OtherThing{
public:
void addElement(std::function<int(Thing*)> func){
this->myfuncs.push_back(func);
}
void toggle(Thing* obj){
std::cout << "toggle .. " << this->myfuncs[0](obj) << std::endl;
}
private:
std::vector<std::function<int(Thing*)>> myfuncs;
};
class Thing: public OtherThing{
public:
Thing(){
std::function<int(Thing*)> myfunc= [](Thing* obj)->int{
std::cout << "from lambda " << obj->value << std::endl;
return obj->value;
};
this->addElement(myfunc);
}
void setValue(int value){
this->value = value;
}
int getValue(){
return this->value;
}
private:
int value;
};
int main() {
// container for things
std::vector<Thing> mythings;
// a thing
Thing a;
// copy is here
mythings.push_back(a);
// test
mythings[0].setValue(666);
mythings[0].toggle(&mythings[0]);
mythings[0].setValue(999);
mythings[0].toggle(&mythings[0]);
return 0;
}
输出:
toggle .. from lambda 666
666
toggle .. from lambda 999
999
我注意到我无法更改存储在 std::vector
或 std::map
中的对象的值。在这两种情况下,作为 toggle()
函数调用的结果,下面代码的输出给出了 "0"
。在矢量外部直接使用对象时不存在此行为。我是否缺少有关 std::vector
或类似容器的信息?我们如何正确地将对象存储在容器中并保持更改其值的能力?
#include <iostream>
#include <functional>
#include <vector>
class OtherThing{
public:
void addElement(std::function<int()> func){
this->myfuncs.push_back(func);
}
void toggle(){
std::cout << "toggle .. " << this->myfuncs[0]() << std::endl;
}
private:
std::vector<std::function<int()>> myfuncs;
};
class Thing: public OtherThing{
public:
Thing(){
std::function<int()> myfunc= [this]()->int{
std::cout << "from lambda " << this->value << std::endl;
return this->value;
};
this->addElement(myfunc);
}
void setValue(int value){
this->value = value;
}
int getValue(){
return this->value;
}
private:
int value;
};
int main() {
// container for things
std::vector<Thing> mythings;
// a thing
Thing a;
mythings.push_back(a);
mythings[0].setValue(666);
mythings[0].toggle();
mythings[0].setValue(999);
mythings[0].toggle();
return 0;
}
输出:
clang++-7 -pthread -std=c++17 -o main main.cpp
./main
toggle .. from lambda 0
0
toggle .. from lambda 0
0
push_back(a)
制作 copy a
。 mythings[0]
returns 对该副本的引用。因此,任何修改 mythings[0]
成员的操作都不会反映在 a
中,反之亦然。
然而,当 a
被 push_back()
复制时,Thing
的编译器生成的复制构造函数将按原样复制 myfuncs
向量,因此a
的构造函数存储在该向量中的 lambda 也按原样复制。该 lambda 捕获了指向 a
的 this
指针,而不是新副本。
因此,当您调用 mythings[0].setValue()
时,您正在修改复制的 Thing
的 value
,但是当您调用 mythings[0].toggle()
时,您正在调用一个 lambda打印 a
的 value
- 一开始就没有初始化 ,所以输出是 indeterminate 直到 a.setValue()
被调用。
要解决此问题,您需要为 Thing
实现自己的复制构造函数,它存储自己的 lambda 捕获复制的 Thing
的 this
指针,而不是存储的副本来自 Thing
的早期 lambda 被复制自,例如:
Thing(const Thing &src){
value = src.value;
std::function<int()> myfunc = [this]()->int{
std::cout << "from copied lambda " << this->value << std::endl;
return this->value;
};
this->addElement(myfunc);
}
我也是根据评论尝试的。老实说,我不喜欢这样。太多的脚本只是为了调用 toggle()
#include <iostream>
#include <functional>
#include <vector>
class Thing;
class OtherThing{
public:
void addElement(std::function<int(Thing*)> func){
this->myfuncs.push_back(func);
}
void toggle(Thing* obj){
std::cout << "toggle .. " << this->myfuncs[0](obj) << std::endl;
}
private:
std::vector<std::function<int(Thing*)>> myfuncs;
};
class Thing: public OtherThing{
public:
Thing(){
std::function<int(Thing*)> myfunc= [](Thing* obj)->int{
std::cout << "from lambda " << obj->value << std::endl;
return obj->value;
};
this->addElement(myfunc);
}
void setValue(int value){
this->value = value;
}
int getValue(){
return this->value;
}
private:
int value;
};
int main() {
// container for things
std::vector<Thing> mythings;
// a thing
Thing a;
// copy is here
mythings.push_back(a);
// test
mythings[0].setValue(666);
mythings[0].toggle(&mythings[0]);
mythings[0].setValue(999);
mythings[0].toggle(&mythings[0]);
return 0;
}
输出:
toggle .. from lambda 666
666
toggle .. from lambda 999
999