为什么emplace_back支持const对象却不支持指向const对象的指针?
问题原因分析
你遇到的编译错误和emplace_back本身无关,核心是容器元素的类型和传入参数不匹配,C++禁止了对应的隐式类型转换:
- 第一个可正常运行的场景中,
collection1的元素类型是std::pair<int, MyData>,你传入const MyData对象时,pair的构造函数会调用MyData的拷贝构造函数,基于const的源对象拷贝生成一个新的非constMyData实例,这个操作是合法的,所以编译正常。 - 第二个报错的场景中,
collection2的元素类型是std::pair<int, MyData*>,你传入的是const MyData*,这是一个指向const对象的指针,要赋值给MyData*(指向非const对象的指针)的话,相当于隐式丢弃了底层const限定,C++标准禁止这种不安全的隐式转换,所以pair构造失败触发模板报错。就算你换成push_back(std::make_pair(1, someDataPtr))也会报同样的错误,和emplace操作没有关系。
解决方案
根据你的实际使用需求可以选择对应方案:
场景1:后续不会通过集合中的指针修改MyData对象(符合你描述的「不修改任何数据」的使用场景)
这是最推荐的方案,完全符合const正确性要求:
直接将集合的元素类型修改为std::pair<int, const MyData*>即可,类型完全匹配,不需要做任何额外转换,emplace_back可以正常调用。
修改后的示例代码:
#include <list> class MyData { }; int main() { std::list<std::pair<int, const MyData*>> collection2{}; // 修改第二个模板参数为const MyData* const MyData someData{}; const MyData* someDataPtr = &someData; collection2.emplace_back(1, someDataPtr); // 编译正常 }
对应你的成员函数场景,只要把collection的类型声明调整即可,函数本身不需要改动:
// 成员函数无需修改 void add_to_schedule(const int id, const MyData* myData) { // some processing this->collection.emplace_back(id, myData); // 正常运行 }
场景2:后续需要通过集合中的指针修改MyData对象
这种情况下你需要保证传入的指针指向的是实际可修改的MyData实例,有两种修改方式:
- 调整函数参数的const限定:将
add_to_schedule的入参改为MyData* myData,从源头保证传入的是指向非const对象的指针,这也是符合const正确性的方案。 - 显式const转换:如果你确定传入的
const MyData*指向的对象本身不是const声明的,可以用const_cast做显式转换,注意如果转换后修改了原本就是const的对象,会触发未定义行为:
void add_to_schedule(const int id, const MyData* myData) { // some processing this->collection.emplace_back(id, const_cast<MyData*>(myData)); }
内容的提问来源于stack exchange,提问作者Verwirrt
相关产品推荐
相关产品推荐

