C++ 复制/移动gcc中的对象会断开其成员lambda
比如说,有一个简单的多态关系:C++ 复制/移动gcc中的对象会断开其成员lambda,c++,gcc,lambda,polymorphism,visitor,C++,Gcc,Lambda,Polymorphism,Visitor,比如说,有一个简单的多态关系: class base { public: void update() const { updater(); } void accept(visitor const &visitor) { visitor_acceptor(visitor); } protected: base(std::function<void()> const &updater, std::func
class base {
public:
void update() const { updater(); }
void accept(visitor const &visitor) {
visitor_acceptor(visitor);
}
protected:
base(std::function<void()> const &updater,
std::function<void(visitor const &)> const &visitor_acceptor)
: updater(updater), visitor_acceptor(visitor_acceptor) {}
protected:
std::function<void()> updater;
std::function<void(visitor const &)> visitor_acceptor;
};
class derived_int : public base {
public:
derived_int() : base(
[this]() { ++value; },
[this](visitor const &visitor) { visitor(value); }
), value(0) {}
protected:
int value;
};
class derived_string : public base {
public:
derived_string() : base(
[this]() { value += '1'; },
[this](visitor const &visitor) { visitor(value); }
), value("") {}
protected:
std::string value;
};
似乎存在某种对象生命周期问题,因为显式创建的变量不会导致任何问题,但我无法准确地指出它。一旦捕获
此
函数对象成员就不适合复制或移动。捕获的this
是一个副本,仍然指向生成lambda的原始实例。您复制的this
可能不再是有效指针,使用它是未定义的行为。它有时可能会起作用,可能会使其他人崩溃,可能会做任何可以想象的事情。不同的编译器可以生成不同的程序集。就语言而言,对于一个实现的UB表达式与另一个实现的UB表达式如何以及为什么不同,没有任何逻辑或理由。如果您试图自己处理移动和复制,您仍然需要创建具有不同捕获值的全新lambda。您将无法提取原始lambda函数体来执行此操作。您可以尝试将此
等效参数添加到函数对象中,而不是捕获此
,但我不确定这是否与您的设计兼容。一个可能的快速解决方法是使您的类型不可复制且不可移动,并始终使用std::unique\u ptr
对其进行管理。如果您从未复制或移动您的类型,则lambda捕获的指针永远不会失效。您仍然可以添加emplace
以使s.emplace(/*..*/)
一旦捕获此
函数对象成员就不适合复制或移动。捕获的this
是一个副本,仍然指向生成lambda的原始实例。您复制的this
可能不再是有效指针,使用它是未定义的行为。它有时可能会起作用,可能会使其他人崩溃,可能会做任何可以想象的事情。不同的编译器可以生成不同的程序集。就语言而言,对于一个实现的UB表达式与另一个实现的UB表达式如何以及为什么不同,没有任何逻辑或理由。如果您试图自己处理移动和复制,您仍然需要创建具有不同捕获值的全新lambda。您将无法提取原始lambda函数体来执行此操作。您可以尝试将此
等效参数添加到函数对象中,而不是捕获此
,但我不确定这是否与您的设计兼容。一个可能的快速解决方法是使您的类型不可复制且不可移动,并始终使用std::unique\u ptr
对其进行管理。如果您从未复制或移动您的类型,则lambda捕获的指针永远不会失效。您仍然可以添加emplace
以使s.emplace(/*..*/)代码>
class storage {
public:
void add(base const &input) { pointers.emplace_back(std::make_unique<base>(input)); }
void add(base &&input) { pointers.emplace_back(std::make_unique<base>(std::move(input))); }
void update() {
for (auto &ptr : pointers)
ptr->update();
}
void print() {
visitor printer;
for (auto &ptr : pointers)
ptr->accept(printer);
}
private:
std::vector<std::unique_ptr<base>> pointers;
};
int main() {
storage s;
derived_int temp1;
derived_string temp2;
s.add(temp1);
s.add(temp2);
s.add(derived_int{});
s.add(derived_string{});
for (size_t i = 0; i < 5; i++)
s.update();
s.print();
}
derived_int: 5
derived_string: 11111
derived_int: -71963
derived_string: 1