在C++中将数组作为const参数传递给方法

14

我希望能够在C++中将const数组参数传递给一个方法。

我知道当你将一个数组传递给方法时,它与传递数组第一个项的指针相同,因此一种简单的方法是使用指针。

void myMethod(int * const inTab)

但有时使用数组更好,例如可以写入数组的大小。


https://dev59.com/X1fUa4cB1Zd3GeqPGUnf#6034056 - user195488
你想要传递一个数组的引用。请参考这个问题及其答案进行讨论。 - D.Shawley
2
为什么不使用std::vector?http://www.parashift.com/c++-faq/arrays-are-evil.html - Keldon Alleyne
2
@avasopht:因为数组并不总是邪恶的,而动态分配有时候却是邪恶的。 - Mike Seymour
是的,非常正确。当然,确保Kevin和其他查看此问题的人知道c++-faq以及与数组使用相关的一些危险是很重要的。如果他们在std::vector上遇到麻烦,至少不太可能出现缓冲区溢出 ;) 同时,他们也可以开始考虑那些位于中间的优雅解决方案,既不分配内存,也不直接访问数组。 - Keldon Alleyne
5个回答

26
您可以使用一个以数组大小为参数的模板:http://ideone.com/0Qhra
template <size_t N>
void myMethod ( const int (& intArray) [N] )
{
    std::cout << "Array of " << N << " ints\n";
    return;
}

编辑: 避免代码膨胀的一种可能方法是编写一个接受指针和大小的函数来执行实际的工作:

void myMethodImpl ( const int * intArray, size_t n );

还有一个简单的模板调用它,它将容易地被内联。

template <size_t N>
void myMethod ( const int (& intArray) [N] )
    { myMethodImpl ( intArray, N ); }

当然,你需要找到一种方法来测试它是否总是能被内联,但你确实可以获得安全性和易用性。即使在它无法被内联的情况下,你也可以在相对较小的代价下获得好处。


1
虽然这种方法是可行的,但并不特别优雅,因为如果我使用不同大小调用myMethod 100次,就会得到100个不同的函数。代码膨胀立即发生。根据函数的实际操作,优化器可能会使用一个函数代替,但在大多数有用的情况下,我认为这是不成立的... - twalberg
@BoBTFish:谢谢你的回复。你知道有没有避免访问数组边界之外元素的解决方案吗?例如:int x = intArray[N]; - Kevin MOLCARD
@twalberg:这是一个很好的观点。你有什么建议吗?也许像我在最初的帖子中写的那样,采用一个更通用但不太强大的方法? - Kevin MOLCARD
1
@KevinMOLCARD 这总是个权衡之间的选择... 如果我知道只有少量的N需要实例化,我可能会采用@BoBTFish最初提出的方案。如果可能存在更多情况,我要么采取他的编辑中提出的另一种方式(通过传递大小作为额外参数),要么将数组及其大小包装在一个小结构体中,并传递对该结构体的引用/指针,以避免有太多的参数。像往常一样,没有一个万能的解决方案。 - twalberg
我喜欢这个技巧,并向所有初级开发人员建议使用它。能够捕获静态C数组(地址和大小),而不仅仅是衰减的指针,并且不必担心大小不同步,这真是太棒了。 - Scott Jones
如果元编程展开了很多N,那么你的代码就存在代码膨胀问题。但是,如果所有手写的调用站点使用不同的N,那么你的代码已经膨胀了。你不能通过一个只有一行的函数使其增长如此之多,这与你的调用站点数量相同。 - v.oddou

8

根据3.9.3:2:

应用于数组类型的任何cv限定符都会影响数组元素类型,而不是数组类型(8.3.4)。

和8.3.4:1:

任何形式为“cv限定符序列N个T的数组”的类型都会调整为“N个cv限定符序列T的数组”,对于“未知边界的T数组”也是如此。

另外,根据8.3.5:5:

确定每个参数的类型后,任何类型为“T的数组”或“返回T的函数”的参数都会被调整为“指向T的指针”或“返回T的函数指针”,分别。

这意味着,在接受数组参数的函数内部,参数类型实际上是指针,并且由于3.9.3:2,指针不带有cv限定符:

void foo(const int parameter[10]) {
    parameter = nullptr;   // this compiles!
}

这不会影响函数本身的类型,因为在8.3.5:5中有另一个条款:

在生成参数类型列表后,任何修改参数类型的顶层cv限定符在形成函数类型时都将被删除。

因此,如果您想能够传递带有cv限定符的数组,则必须通过引用传递:

void foo(const int (&parameter)[10]);

5

如果您需要获取数组的大小:

template < std::size_t Size >
void myMethod( const int ( &inTab )[ Size ] );

5

我不确定这是否是您询问的内容,但也许这正是您所寻找的。

(该文本已翻译成中文,并且保留了HTML标记)
void func (const int array[10])
{
    //array[0] = 12345; // this wouldn't compile, so 'const' works
}

int main ()
{
    int array[10];
    func(array);
}

array = 0 虽然能编译通过,但这不是 OP 想要的。 - a3f
@a3f,为什么他不想要呢?func内部的array=0不会影响到外部。 - ricab

-1
尝试使用`std::vector`。
void myMethod(const std::vector<int> &inTab);

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