C++ 数组[1]会发生什么变化

C++ 数组[1]会发生什么变化,c++,c,arrays,optimization,C++,C,Arrays,Optimization,我有一个很大的代码块,用于获取一个数组并处理它。在当前项目中只有一个元素,因此我没有将变量更改为char,而是将其声明为char数组[1]。这样我就不需要修改我的代码,也不需要冒添加任何bug的风险,而且如果需求增长,我可以很容易地增加bug 它看起来不错,但我对引擎盖下发生的事情感到好奇,我是在浪费内存吗?这是否增加了额外的处理时间,编译器是否会对其进行优化,以便在我输入时不会有什么不同 有谁能解释一下这样使用数组有什么可能的缺点吗 我用C和C++,它们之间有什么不同吗?< /P> < P>听

我有一个很大的代码块,用于获取一个数组并处理它。在当前项目中只有一个元素,因此我没有将变量更改为char,而是将其声明为char数组[1]。这样我就不需要修改我的代码,也不需要冒添加任何bug的风险,而且如果需求增长,我可以很容易地增加bug

它看起来不错,但我对引擎盖下发生的事情感到好奇,我是在浪费内存吗?这是否增加了额外的处理时间,编译器是否会对其进行优化,以便在我输入时不会有什么不同

有谁能解释一下这样使用数组有什么可能的缺点吗


<>我用C和C++,它们之间有什么不同吗?< /P> < P>听起来是个好策略,没有缺点。在C或C++中,你绝对不会浪费内存。大小为1的数组占用的内存与类型相同的变量占用的内存相同


编译器可能会生成微观上效率较低的代码,但这确实不值得担心。

标准规定允许您获取非数组对象的地址,并将其视为大小为1的数组(因此您可以将指针指向末尾)

参见C++11标准第§5.7.4节:

对于这些运算符,指向非阵列对象的指针 行为与指向数组的第一个元素的指针相同 长度1,对象类型作为其元素类型


首先,您的代码是有效的,但是如果您关心缺点,我可以看到下面列出的问题:

使用数组,当您不小心地在数组中循环时,您可以增加使用越界访问的机会

另一个缺点是数组不与多态性交互。有时您试图将派生对象存储到基类型的数组中,对象将被切片,您可能不会注意到


所以我不会写数组[1]代码。希望这能回答您的一些问题。

这里我们面临两个代码块

  • 设计用于获取数组并工作的一大块代码 通过它
  • 使用前一代码块的一段代码 一些数据
构造代码。

  (a) void work( char  c );
  (b) void work( char& c );
  (c) void work( const char v[], size_t size);
  (d) void work(       char v[], size_t size);
大代码块应该是一个可能被划分为几个子函数的函数。 另一段代码将调用此函数

char c;
c = 'b';
work( &c, 1 );
//////
char a[1];
a[0] = 'b';
work( a, 1 );
函数的参数。数组或单个字符。

  (a) void work( char  c );
  (b) void work( char& c );
  (c) void work( const char v[], size_t size);
  (d) void work(       char v[], size_t size);
如果工作类型对阵列没有意义,则应使用选项(a)和(b)。事实并非如此。
如果工作对阵列有意义,则应使用选项(c)和(d)

所以使用数组

保存数据的变量。数组或单个字符。

  (a) void work( char  c );
  (b) void work( char& c );
  (c) void work( const char v[], size_t size);
  (d) void work(       char v[], size_t size);
如果您只需要保存一个字符,那么就使用一个非数组字符。您仍然可以调用数组函数

char c;
c = 'b';
work( &c, 1 );
//////
char a[1];
a[0] = 'b';
work( a, 1 );
work函数将单个变量和数组视为大小为1的数组。在这两种情况下,代码都可以正常工作,并且不会影响效率

测试

让我们看看真正的代码是否包含我以前的语句

#include <iostream>
#include <ctime>
#include <vector>
#include <cstddef>
#include <chrono>

using namespace std;

unsigned long miliTime()
{
    return std::chrono::system_clock::now().time_since_epoch() /
           std::chrono::milliseconds(1);
}
// An hypotetical work function with arrays
void workArray( char v[], size_t size )
{
  for ( size_t n=0; n<size; ++n )
  {
    // large block of code
    for ( int i=0; i<1000; ++i )
    {
      v[n] += 3 + i;
      if (v[n] == '3' )
        v[n] = 'J' - v[n];
      v[n] = toupper( v[n] ) + '-';
    }
  }
}

// Same function just for a single character
void workSingle( char& c )
{
  // large block of code
  for ( int i=0; i<1000; ++i )
  {
    c += 3 + i;
    if (c == '3' )
      c = 'J' - c;
    c = toupper( c ) + '-';
  }
}

int main(void)
{
  const long int repeats =1000000;
  long int n;
  unsigned long start;
  double dif;

  start = miliTime();
  char c;
  c = 'b';
  for ( n=0; n<repeats; ++n)
    workArray( &c, 1 );
  dif = miliTime() - start;
  cout << "Result = " << c << endl;
  cout << "Non-array var passed to array code = " << dif << " ms" << endl;

  start = miliTime();
  char a[1];
  a[0] = 'b';
  for ( n=0; n<repeats; ++n)
    workArray( a, 1 );
  dif = miliTime() - start;
  cout << "Result = " << a[0] << endl;
  cout << "Array var passed to array code = " << dif << "ms" << endl;

  start = miliTime();
  char c2;
  c2 = 'b';
  for ( n=0; n<repeats; ++n)
    workSingle( c2 );
  dif = miliTime() - start;
  cout << "Result = " << c2 << endl;
  cout << "Non-array var passed to non-array code = " << dif << "ms" << endl;

  start = miliTime();
  char a2[1];
  a2[0] = 'b';
  for ( n=0; n<repeats; ++n)
    workSingle( a2[0] );
  dif = miliTime() - start;
  cout << "Result = " << a2[0] << endl;
  cout << "Array var passed to non-array code = " << dif << "ms" << endl;
}
我得到这个输出:
结果=z
非数组变量传递到数组代码=5520毫秒
结果=z
传递给数组代码的数组变量=5515ms
结果=z
传递给非数组代码的非数组变量=5203ms
结果=z
传递给非数组代码的数组变量=5203ms

正如预期的那样,结果总是一样的。 对于这两种实现,将数组或非数组变量传递给work函数没有明显区别。

workSingle比workArray快6%
外部循环的执行(工作单中不存在)不太可能是原因,因为内部循环执行了1000次。原因可能是由于间接寻址导致访问v[n]比访问c慢。
虽然如果更改从std::cin读取的全局变量的内部循环中的1000,那么workSingle实际上比workArray提供的时间慢

某些优化、缓存未命中或其他低级内容可能是原因。我不会为了工作效率的不确定性而牺牲workArray的可重用性,除非时间非常关键,您愿意进入组装级别

结论。

  (a) void work( char  c );
  (b) void work( char& c );
  (c) void work( const char v[], size_t size);
  (d) void work(       char v[], size_t size);
将变量声明为非数组,因为它只需包含一个字符。
将大部分代码实现为接受数组参数的函数。如果它这么大,可能会分成几个小节


本帖仅在

+1
下向公众授权,以防止一个错误造成的循环。我希望特别是在C. Good点,但是由于OP表示基于数组的代码已经存在,我会考虑可能的越界错误,因为尝试在<代码>数组[1 ] < /Cord-VIDEE中得到奖励,因为它可能会在一般的代码>数组[N]中捕获bug。尚未找到的代码。数组如何以非数组变量引起的方式导致切片?认为A源于B.A;B,b2[1];b=a;b2[0]=a;你在两个作业中都得到了切片。在b3&=a中不会得到切片;但这是一个参考,而不是第一个问题的内容。多态性也有同样的原因。我记得当试图(有意地)使用
-D\u-FORTIFY\u源代码(gcc/glibc)溢出
char[n]
时,出现了一些奇怪的问题。这个选项显然告诉GCC插入运行时哨兵/边界检查,我永远不会使用选项(b),因为我不希望
work(foo)
修改foo。对于不熟悉
work()
内部工作原理的读者来说,这是一个地雷。如果您想修改一个参数,那么就这样说,并要求使用
voidwork(char*c)的指针<代码>工作(&foo)
清楚地告诉读者,他应该期望foo会改变。不,工作(&foo)不会改变