为何std::move_only_function的调用运算符非const?与std::function有何不同?
std::move_only_function调用运算符非const的原因
std::function的调用运算符设为const,是因为它设计时默认存储可拷贝、调用时不修改自身状态的可调用对象,调用过程仅转发函数调用,不会改动自身成员。而std::move_only_function的设计目标是支持仅可移动不可拷贝的可调用对象,这类对象的调用逻辑往往涉及自身状态的修改,因此它的调用运算符不能设为const,具体原因和可能修改的内容如下:
核心原因:适配移动-only可调用对象的特性
std::move_only_function允许存储各种移动-only类型的可调用对象——比如带移动捕获的lambda、std::packaged_task的移动实例、自定义的仅支持移动的函数对象等。这些对象的operator()本身往往是非const的,调用时会修改自身状态,std::move_only_function作为容器必须转发这类调用,因此自身的调用运算符不能是const(否则无法调用非const的operator())。
调用时可能修改的成员/状态
- 存储的目标可调用对象本身:如果存储的是一个非const的移动-only函数对象,调用时会直接修改该对象的内部状态(比如lambda里捕获的移动-only变量、函数对象的成员变量等)。在MSVC的实现中,若启用小对象优化,这个对象直接存在std::move_only_function的内部缓冲区里,调用时会直接修改缓冲区中的内容;若对象较大,则通过内部指针指向堆内存,调用时修改堆上的对象实例。
- 一次性可调用对象的有效性状态:部分移动-only可调用对象是“一次性”的(比如
std::packaged_task移动后只能调用一次),调用后对象会变为无效状态。std::move_only_function需要允许这种状态变更,因此调用运算符不能是const。 - 内部管理的辅助状态:MSVC实现中,std::move_only_function可能包含一些用于类型擦除、对象生命周期管理的内部成员(比如虚函数表指针、存储标记等),虽然这类成员通常不会被修改,但为了兼容上述需要修改对象本身的场景,整体调用运算符只能设为非const。
内容的提问来源于stack exchange,提问作者TwistedBlizzard
相关产品推荐
相关产品推荐

