一般问题:在 C/C++ 中作为指针传递什么
General question: What to pass as pointer in C/C++?
嘿,我想知道是否值得通过指针传递原始的单个值,如int
、float
、double
或char
?可能不值得!?但是,如果您只是通过指针传递所有内容,这是否会使程序变慢?你应该总是只将数组作为指针传递吗?谢谢!
我想知道是否值得通过指针传递原始的单个值,如 int、float、double 或 char?
你想完成什么?是否希望能够写入传入的值?还是您只需要使用它?如果你想写它,惯用的方式是通过引用传递。如果您不需要写入它,则最好避免意外写入它并按值传递的任何风险。按值传递将创建变量的副本以供本地使用。(顺便说一句,如果您不想复制并且想要一定程度的安全性,您可以通过 const 引用)
但是,如果您只是通过指针传递所有内容,这是否会使程序变慢?
很难说。取决于很多事情。在按值传递和按引用(或指针)传递中,您创建一个新的基元类型。按值传递,您正在制作副本。在通过引用/指针传递时,您将地址传递给原始地址。但是,在后一种情况下,您需要额外的内存提取,该内存可能会缓存,也可能不会缓存。如果不测量它,很难说 100%。
话虽如此,我怀疑差异是否明显。编译器可能能够在许多按值传递的情况下优化副本,如本文所述。(感谢空格 C0wb0y)。
你应该总是只将数组作为指针传递吗?
由此。
C++不可能按值将完整的内存块作为参数传递给函数,但允许我们传递其地址。
传递数组:
int foo(int bar[], unsigned int length)
{
// do stuff with bar but don't go past length
}
我建议避免使用数组并使用std::vector,它具有更容易理解的复制语义。
如果您关心的是速度,那么通过指针传递基元值可能不值得 - 然后您就有"间接"的开销来访问该值。
但是,指针通常是"总线的宽度",这意味着处理器可以一次发送整个值,而不是"移位"值以发送总线。 因此,指针在总线上的传输速度可能比较小的类型(如 char
)更快。 这就是为什么旧的Cray计算机曾经将其char
值设为32位(当时总线的宽度)的原因。
在处理大型对象(如类或数组)时,传递指针比将整个对象复制到堆栈上更快。这适用于 OOP,例如
查看您最喜欢的C++教科书,了解"输出参数"的讨论。
将指针用于输出参数而不是引用的一些优点是:
- 没有
令人惊讶的行为,没有远距离操作,呼叫站点和调用方的语义都很清楚。
与 C 的兼容性(您的问题标题表明这一点很重要)
从共享库或 DLL 导出的函数可由其他语言使用,不应使用仅C++功能(如引用)。
您很少需要通过指针传递任何内容。如果需要修改参数的值,或者想要防止复制,则按引用传递,否则按值传递。
请注意,防止复制也可以通过复制省略来完成,因此您必须非常小心,不要陷入过早优化的陷阱。这实际上会使您的代码变慢。
你的问题没有真正的答案,除了我倾向于记住的几个规则:char 是 8 个字节,指针是 4 个字节,因此切勿将单个 char 作为指针传递。在 int 和 float 等东西与指针大小相同但必须引用指针之后,从技术上讲需要更多时间
如果我们去奔腾 i386 汇编程序:
在 C 中的参数"a"寄存器中加载值,该参数为 int:
movl 8(%ebp),%eax
同样的事情,但作为指针传递:
movl 8(%ebp),%eax
movl (%eax),%eax
必须取消引用指针需要另一个内存操作,因此理论上(不确定是否在现实生活中)传递指针的时间更长......出现内存问题后。如果你想有效地编码,所有组合类型(类,结构,数组......)都必须通过指针传递。想象一下,用一种 16 字节的类型做一个递归函数,该函数通过 copy 传递 1000 次调用,在堆栈中产生 16000 字节(你真的不想这样吗:)?
因此,为了使它简短明了:查看您的类型的大小,如果它大于指针传递它,否则通过副本传递它......
值和对象传递基元类型作为const
引用。尽可能避免指针。取消引用指针有一些开销,并且会使代码混乱。比较以下两个版本的factorial
函数:
// which version of factorial is shorter and easy to use?
int factorial_1 (int* number)
{
if ((*number) <= 1)
return 1;
int tmp = (*number) - 1;
return (*number) * factorial_1 (&tmp);
}
// Usage:
int r = 10;
factorial_1 (&r); // => 3628800
int factorial_2 (int number)
{
return (number <= 1) ? 1 : (number * factorial_2 (number - 1));
}
// Usage:
// No need for the temporary variable to hold the argument.
factorial_1 (10); // => 3628800
调试变得困难,因为您无法说出对象的值何时何地可以更改:
int a = 10;
// f cound modify a, you cannot guarantee g that a is still 10.
f (&a);
g (&a);
首选 vector
类而不是数组。它可以根据需要增长和收缩,并跟踪其大小。访问元素vector
方式与数组兼容:
int add_all (const std::vector<int>& vec)
{
size_t sz = vec.size ();
int sum = 0;
for (size_t i = 0; i < sz; ++i)
sum += vec[i];
}
NO中,您唯一会传递非常量引用的情况是函数需要输出参数。
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值
- 初始化或分配空字符串文字到指向 C 中的 char 的指针或指向 C++ 中 const char 的指针的原因是什么
- int数据类型的指针指向的是什么,如果是一个类的私有数据成员,我们创建了该类的两个对象?
- 使用基类指针调用基类的值构造函数的语法是什么?
- 将指针分配给另一个指针时会发生什么情况?
- 当该数组的索引中没有元素时,指针指向什么?
- C++:Lambda 函数指针转换的用例是什么?
- C++关于指针和使用函数将它们启动到堆的行为究竟是什么?
- 这个失败的测试是将零添加到空指针未定义的行为、编译器错误还是其他什么?
- 使用共享指针时,从共享指针本身释放内存的机制是什么
- 空指针常量 (nullptr)、空指针值和空成员指针值之间有什么区别?
- 什么更好?返回对象指针列表?或返回指向对象列表的指针?
- 什么是更好的做法?通过指针或标识符传递类成员?
- 如果我在 const 函数上使用指针,我可以返回什么?
- 为什么此指针值不能转换为整数的规则是什么?
- 在自定义 std::vector-like 容器中处理指针和非指针模板类型的最佳方法是什么?
- 在什么情况下,需要共享智能指针而无法使用唯一指针?
- 以下与指针相关的代码的输出是什么?
- 指向数组基址的指针而不是指向第一个元素的指针有什么优点?
- C++中的指针.什么类型的对象