C++中如何将动态声明的数组作为常量传递

4

我使用以下函数动态创建了一个数组:

//..
    double ** allocate_2d(const int wd1, const int wd2){
    double **array = new double*[wd1];

    for(int idx=0; idx<wd1; idx++)
    {
        array[idx] = new double[wd2];
    }

    return array;
}

我希望将生成的数组作为常量参数传递到函数中。我希望在函数内部该数组是“只读”的。
func(const double ** array)
{
    // computations using array
}

然而我收到了以下错误信息:invalid conversion from ‘double**’ to ‘const double**’ 是否有可能做到这样的事情?

8
在C++中,每当你想到“动态数组”时,下一个想法几乎总是std::vector。使用std::vector,你将不会有现在的问题(我知道即使我找不到它,但这个问题已经有重复的了)。 - Some programmer dude
谢谢。我会尝试的。但我仍然想了解为什么它不起作用。 - EssentialAnonymity
2
在C++中,如果你关心性能和效率(这通常是选择C++的原因),每当你想到“多维数组”时,下一个想法应该是将其元素存储在一维数组中;)。 - Daniel Langr
1
请参见 http://c-faq.com/ansi/constmismatch.html 了解为什么不允许这样做。 - interjay
2个回答

4

OP的签名原因

func(const double ** array){
    // computations using array
}

在将 double ** 作为参数传递时产生错误,这是由于资格转换规则导致的。
引用 https://en.cppreference.com/w/cpp/language/implicit_conversion(重点在于我):

资格转换

  • 类型为指向经过cv-qualified类型T修饰的指针的prvalue可以转换为指向更多经过cv修饰的同类型T的prvalue指针(也就是说,可以添加constness和volatility)。
  • [...]

"更多"的cv-qualified意味着:

  • 未经修饰的类型指针可以转换为const类型指针;
  • [...]

对于多级指针,有以下限制:一个多级指针P1,它是一个cv10-限定的指向cv11-限定的指向...cv1n-1-限定的指向cv1n-限定的T的指针,只有在以下情况下才能转换为多级指针P2,它是一个cv20-限定的指向cv21-限定的指向...cv2n-1-限定的指向cv2n-限定的T的指针:

  • 两个指针的级数n相同;
  • 如果P1的某个级别(除了零级)的cv1k限定中有一个const,则P2的相同级别的cv2k也必须有一个const;
  • [...]
  • 如果在某个级别k上,P2比P1更cv-qualified,则在每个单独级别(除了零级)的P2上直到k都必须有一个const:cv21、cv22 ... cv2k
  • [...]
  • 零级由非多级资格转换规则处理。
char** p = 0;
const char** p1 = p; // 错误:级别2更cv-qualified,但级别1不是const
const char* const * p2 = p; // 正确:级别2更cv-qualified,
                            // 并在级别1添加了const

请注意,在C编程语言中,只能将const/volatile添加到第一级:

char** p = 0;
char * const* p1 = p; // 在C和C++中都正确
const char* const * p2 = p; // 在C中错误,在C++中正确
因此,为了强制实现常量性,需要将签名更改为
void func(double const * const * array) {
    // ...               ^^^^^ 
}

话虽如此,如果可能的话,我强烈建议更改整体设计并避免使用动态分配的不规则数组。


2
你应该尝试解释一下为什么OP的原始尝试const double ** array不能工作。 - Mark Ingram

-2

你可以使用const_cast来向对象添加const属性(需要显式转换)。

double **p = allocate_2d(100,200);

// populate p

func(const_cast<const double**>(p));//array pointed by p will be read only inside func

不过,你需要考虑是否真的需要在那里使用 const


1
不,解决方案是使“func”定义正确。 - Mark Ingram
不,人们绝对不会这样做。如果您想传达一个函数不修改参数的信息,那么请将该参数标记为“const”,以便编译器防止修改,并确保正确的类型通过。 - Mark Ingram
@Mark Ingram,是的,那可能是正确的解决方案。然而,有时人们使用“const”来让其他人知道在函数中对象不会被改变。 - dsp_user
@dsp_user 类的方法后面的const与此问题无关。 - Bernhard
@Bernhard,我从未在任何地方提到过类。你具体是什么意思? - dsp_user
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接