更改标准向量 C++ 中对象的值

Changing values of objects in std vector c++

我注意到我无法更改存储在 std::vectorstd::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 amythings[0] returns 对该副本的引用。因此,任何修改 mythings[0] 成员的操作都不会反映在 a 中,反之亦然。

然而,当 apush_back() 复制时,Thing 的编译器生成的复制构造函数将按原样复制 myfuncs 向量,因此a 的构造函数存储在该向量中的 lambda 也按原样复制。该 lambda 捕获了指向 athis 指针,而不是新副本。

因此,当您调用 mythings[0].setValue() 时,您正在修改复制的 Thingvalue,但是当您调用 mythings[0].toggle() 时,您正在调用一个 lambda打印 avalue - 一开始就没有初始化 ,所以输出是 indeterminate 直到 a.setValue() 被调用。

要解决此问题,您需要为 Thing 实现自己的复制构造函数,它存储自己的 lambda 捕获复制的 Thingthis 指针,而不是存储的副本来自 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);
}

Online Demo

我也是根据评论尝试的。老实说,我不喜欢这样。太多的脚本只是为了调用 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