双指针函数参数可变性组合及编译错误问题
C++双指针const转换编译错误解析
我尝试将单指针作为双指针参数传入函数,要求不修改原单指针的前提下修改该指针指向的数据,为此整理了四种带const修饰的双指针组合代码,但调用foo4时触发编译错误,代码及错误信息如下:
#include <iostream> // 禁止修改外层指针,禁止修改指向的数据 void foo1(const int* const* dp) { std::cout << "foo1\n"; std::cout << **dp << std::endl; int i = 4; int* p = &i; // *dp = p; // 编译错误:无法修改外层指针 // **dp = i; // 编译错误:无法修改指向的数据 dp = &p; // 允许修改函数内部的dp指针本身 } // 允许修改外层指针,允许修改指向的数据 void foo2(int** dp) { std::cout << "foo2\n"; std::cout << **dp << std::endl; **dp = 12; // 修改指向的数据 // *dp = nullptr; // 可以修改外层指针 } // 禁止修改外层指针,允许修改指向的数据 void foo3(int* const* dp) { std::cout << "foo3\n"; std::cout << **dp << std::endl; // *dp = nullptr; // 编译错误:无法修改外层指针 **dp = 45; // 修改指向的数据 } // 允许修改外层指针,禁止修改指向的数据 void foo4(const int** dp) { std::cout << "foo4\n"; std::cout << **dp << std::endl; // **dp = 5; // 编译错误:无法修改指向的数据 *dp = nullptr; // 修改外层指针 } int main(int argc, char** argv) { int i = 3; int* p = &i; foo1(&p); foo2(&p); foo3(&p); foo4(&p); // 此处编译失败 }
编译错误信息(翻译为中文):
<source>:53:10: 错误:无法从'int**'隐式转换为'const int**' [-fpermissive] 53 | foo4(&p); | ^~ | | | int** <source>:36:23: 注意:正在初始化'void foo4(const int**)'的第1个参数 36 | void foo4(const int** dp) { |
错误原因
这是C++的const类型安全机制在起作用。直接将int**转换为const int**会导致const语义被破坏的风险,举个典型的漏洞场景:
int* p; const int** pp = &p; // 假设编译器允许这种转换 const int ci = 10; *pp = &ci; // 让p指向const变量ci *p = 20; // 通过p修改了const变量ci,违反了const的只读约定
为了避免这种安全问题,编译器直接禁止了int**到const int**的隐式转换。
解决方案
根据你的需求,分两种情况处理:
情况1:需要修改原单指针变量(比如让p变为nullptr),同时禁止修改指向的数据
这种情况下,你需要将原单指针声明为const int*类型,这样&p就是const int**类型,可以直接传入foo4:
int i = 3; const int* p = &i; // 将p声明为指向const int的指针 foo4(&p); // 编译通过
此时p本身可以被修改指向其他const int,但无法通过p修改指向的数据,完全符合foo4的设计意图。
情况2:不需要修改原单指针,仅需要修改指向的数据
这种情况下,foo3的设计完全符合你的初始需求:它的参数int* const* dp禁止修改外层指针(原单指针p不会被改变),但允许修改**dp(指针指向的数据),调用也不会有任何问题。
如果只是为了让现有代码编译通过,且不需要修改原单指针p,可以临时将p转换为const int*后传入:
const int* temp_p = p; foo4(&temp_p);
注意:这种方式修改的是临时变量temp_p,不会影响原指针p的值。
内容的提问来源于stack exchange,提问作者Harry
相关产品推荐
相关产品推荐

