【问题标题】:Sizeof() function not working over a constant array C++Sizeof() 函数不适用于常量数组 C++
【发布时间】:2015-10-29 20:52:18
【问题描述】:

在开始之前,我正在使用 VS2015 C++ 语言编译程序。当我尝试确定两个常量数组的大小时,问题是编译错误。问题涉及的类:

头文件:

#ifndef RACE_H_
#define RACE_H_
class Race
{
    private:
        static const int PILOT_POINTS[];
        static const double TEAM_AWARDS[];
}
#endif

源文件:

#include "Race.h"
const int PILOT_POINTS[] = { 25, 18, 15, 12, 10, 8, 6, 4, 2, 1 };
const double TEAM_AWARDS[] = { 100000, 75000, 50000, 25000, 15000, 10000 };

部分错误:

sizeof(TEAM_AWARDS) / sizeof(TEAM_AWARDS[0]))
sizeof(PILOT_POINTS) / sizeof(PILOT_POINTS[0]))

编译器说:

错误 2070 const int[] 操作数 sizeof 无效。

不允许使用不完整的类型。

错误 2070 const double[] 操作数 sizeof 无效。

不允许使用不完整的类型。

我可以使用 extern 来解决这个问题吗?如果是,我应该如何使用它?

【问题讨论】:

  • 有什么理由不使用const std::vector<int> PILOT_POINTS?然后你可以使用PILOT_POINTS.size()
  • sizeof 是运算符,而不是函数。
  • 另外const int PILOT_POINTS[] = { 25, 18, 15, 12, 10, 8, 6, 4, 2, 1 }; 不是从类中初始化数组,而是创建一个全局数组。您需要将其更改为const int Race::PILOT_POINTS[] = { 25, 18, 15, 12, 10, 8, 6, 4, 2, 1 };
  • @CoryKramer: std::vector::size() 不是编译时常量。 sizeof 是。如果您将其用作模板非类型参数、初始化枚举或用作另一个数组的维度,则非常重要。
  • @BenVoigt 好点,在这种情况下他们可以使用std::array,因为std::array::size 是编译时间常数,即constexpr

标签: c++ arrays constants sizeof


【解决方案1】:

问题是您已声明数组,但在调用sizeof 运算符时尚未定义它们。

此外,您不能只将定义移到标题中,因为只能以这种方式定义整数类型:

如果一个非易失性 const 静态数据成员是整数或枚举类型,它在类定义中的声明可以指定一个大括号或等式初始化器,其中每个作为赋值表达式的初始化器子句都是一个常量表达。可以在类定义中使用 constexpr 说明符声明文字类型的静态数据成员;如果是这样,它的声明应指定一个大括号或等式初始化器,其中作为赋值表达式的每个初始化器子句都是一个常量表达式......(第 9.4.2/3 节)

C 风格的可变长度数组不是整数,因为它们的长度在定义之前是未知的。

要解决这个问题,需要在数组中使用长度说明符:

#ifndef RACE_H_
#define RACE_H_
class Race
{
    private:
        static const int PILOT_POINTS[10];
        static const double TEAM_AWARDS[6];
}
#endif

这是额外的麻烦,因为现在如果数组改变大小,你必须改变长度,但这是必要的。

或者,您可以使用constexpr,并将整个定义放在标题中。这样,您可以省略数组长度。

#ifndef RACE_H_
#define RACE_H_
class Race
{
    private:
        static constexpr int PILOT_POINTS[]
                = { 25, 18, 15, 12, 10, 8, 6, 4, 2, 1 };
        static constexpr double TEAM_AWARDS[]
                = { 100000, 75000, 50000, 25000, 15000, 10000 };
}
#endif

另外,您可以尝试@CoryKramer 在评论中的建议,并使用vector。初始化它和查找大小的运行时间成本非常低,但这并不重要。

【讨论】:

  • 如果你搞砸了并且在声明中放了一个太大的计数,这将是一个无声的错误,并且数组的末尾将被零填充。
  • 这很好。如果您选择 1 号门,请确保您的计数正确,并为维护者的定义添加注释。 2 号门消除了这种错误机会。
【解决方案2】:

您只需在声明中提供尺寸即可。来自[dcl.array]:

除以下说明外,如果省略常量表达式,则 D 的标识符是“T 的未知边界的衍生声明器类型列表数组”,一个不完整的对象类型

和[expr.sizeof]:

sizeof 运算符不应应用于具有函数或不完整类型的表达式[...]

没有常量表达式大小的数组的例外情况是您提供了一个初始化器(例如int a[] = {1, 2})或者当数组之前声明了一个大小。因此,在这种情况下,您可以提供标头的大小或初始化程序:

static const int PILOT_POINTS[10];    
static const int PILOT_POINTS[] = { 25, 18, 15, 12, 10, 8, 6, 4, 2, 1 };

或者只是使用vector,这样您就可以在源代码中对其进行初始化,并获得vector 相对于原始C 数组的所有其他优点:

static const std::vector<int> PILOT_POINTS;

【讨论】:

    【解决方案3】:

    其他答案已经解决了您需要定义数组的事实。为了完整起见,我会提到您获取数组大小的方法是“the C version”。 C++有更好的办法std::extent

    #include <iostream>
    #include <type_traits>
    
    struct Race
    {
        static const int PILOT_POINTS[];
        static const double TEAM_AWARDS[];
    };
    
    const int Race::PILOT_POINTS[] = { 25, 18, 15, 12, 10, 8, 6, 4, 2, 1 };
    const double Race::TEAM_AWARDS[] = { 100000, 75000, 50000, 25000, 15000, 10000 };
    
    int main()
    {
        ::std::wcout << ( sizeof( Race::PILOT_POINTS ) / sizeof( Race::PILOT_POINTS[ 0 ] ) ) << L' '
            << ( sizeof( Race::TEAM_AWARDS ) / sizeof( Race::TEAM_AWARDS[ 0 ] ) ) << L'\n'
            << std::extent< decltype( Race::PILOT_POINTS ) >::value << L' '
            << std::extent< decltype( Race::TEAM_AWARDS ) >::value;
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2017-12-11
      • 2011-06-05
      • 1970-01-01
      • 1970-01-01
      • 2017-04-27
      • 1970-01-01
      • 1970-01-01
      • 2014-09-13
      • 2020-11-16
      相关资源
      最近更新 更多