4 回答
TA贡献1852条经验 获得超7个赞
C ++ 11的经验法则:
通过按值时,除
你不需要对象的所有权和一个简单的别名会做,在这种情况下你通过
const
引用传递,你必须改变对象,在这种情况下,使用非
const
左值引用传递,您将派生类的对象作为基类传递,在这种情况下,您需要通过引用传递。(使用以前的规则来确定是否通过
const
引用传递。)
几乎从不建议通过指针传递。可选参数最好表示为a std::optional
(boost::optional
对于较旧的std libs),并且通过引用完成别名。
C ++ 11的移动语义使得即使对于复杂对象,传递和返回值也更具吸引力。
C ++ 03的经验法则:
通过const
引用传递参数,除非
它们将在函数内部进行更改,并且此类更改应反映在外部,在这种情况下,您将通过非
const
引用传递该函数应该是可调用的,没有任何参数,在这种情况下,你通过指针传递,以便用户可以传递
NULL
/0
/nullptr
; 应用先前的规则来确定是否应该通过指向const
参数的指针它们是内置类型,可以通过复制传递
它们是在函数内部将被改变并且这些变化应不被外部的反射,在这种情况下,可以通过复制通过(一个替代方法是,根据前述规则,以通过和使函数的内部副本)
(这里,“按值传递”被称为“按副本传递”,因为按值传递总是在C ++中创建一个副本03)
还有更多,但这些初学者的规则会让你走得更远。
TA贡献1934条经验 获得超2个赞
C ++和Java中的调用约定存在一些差异。在C ++中,从技术上讲,只有两种约定:按值传递和按引用传递,一些文献包括第三次传递指针约定(实际上是指针类型的值传递)。最重要的是,您可以将const-ness添加到参数的类型中,从而增强语义。
通过引用传递
通过引用传递意味着该函数将在概念上接收您的对象实例而不是它的副本。该引用在概念上是调用上下文中使用的对象的别名,并且不能为null。在函数内执行的所有操作都适用于函数外部的对象。此约定在Java或C中不可用。
按值传递(并按指针传递)
编译器将在调用上下文中生成对象的副本,并在函数内使用该副本。在函数内执行的所有操作都是对副本完成的,而不是外部元素。这是Java中基本类型的约定。
它的一个特殊版本是将指针(对象的地址)传递给函数。函数接收指针,并且应用于指针本身的任何和所有操作都应用于副本(指针),另一方面,应用于解除引用指针的操作将应用于该内存位置的对象实例,因此该函数可能有副作用。使用指向对象的指针传递值的效果将允许内部函数修改外部值,如使用pass-by-reference,并且还允许可选值(传递空指针)。
这是C函数需要修改外部变量时使用的约定,以及Java中使用引用类型的约定:引用被复制,但引用的对象是相同的:引用/指针的更改在外部不可见该函数,但对指向内存的更改是。
将const添加到等式中
在C ++中,您可以在定义不同级别的变量,指针和引用时为对象分配常量。您可以将变量声明为常量,可以声明对常量实例的引用,并且可以定义所有指向常量对象的指针,指向可变对象的常量指针和指向常量元素的常量指针。相反,在Java中,您只能定义一个级别的常量ness(final关键字):变量的类型(基本类型的实例,引用类型的引用),但是您不能定义对不可变元素的引用(除非类本身是不可变的)。
这在C ++调用约定中广泛使用。当对象很小时,您可以按值传递对象。编译器将生成一个副本,但该副本不是一个昂贵的操作。对于任何其他类型,如果函数不会更改对象,则可以将引用传递给该类型的常量实例(通常称为常量引用)。这不会复制对象,而是将其传递给函数。但同时编译器将保证在函数内部不更改对象。
经验法则
这是一些要遵循的基本规则:
首选基本类型的传值
对于其他类型的引用,首选引用传递
如果函数需要修改参数,请使用pass-by-reference
如果参数是可选的,请使用pass-by-pointer(如果不应修改可选值,则为常量)
这些规则还有其他小的偏差,第一个是处理对象的所有权。当使用new动态分配对象时,必须使用delete(或其[]版本)对其进行解除分配。负责销毁对象的对象或函数被视为资源的所有者。当在一段代码中创建动态分配的对象,但是所有权被转移到另一个元素时,通常使用pass-by-pointer语义,或者如果可能的话使用智能指针。
边注
重要的是要坚持C ++和Java引用之间差异的重要性。在C ++中,引用在概念上是对象的实例,而不是对象的访问者。最简单的例子是实现交换功能:
// C++class Type; // defined somewhere before, with the appropriate operationsvoid swap( Type & a, Type & b ) { Type tmp = a; a = b; b = tmp;}int main() { Type a, b; Type old_a = a, old_b = b; swap( a, b ); assert( a == old_b ); assert( b == old_a ); }
上面的交换函数通过使用引用来更改其参数。Java中最接近的代码:
public class C { // ... public static void swap( C a, C b ) { C tmp = a; a = b; b = tmp; } public static void main( String args[] ) { C a = new C(); C b = new C(); C old_a = a; C old_b = b; swap( a, b ); // a and b remain unchanged a==old_a, and b==old_b }}
Java版本的代码将在内部修改引用的副本,但不会在外部修改实际的对象。Java引用是没有指针算术的C指针,它们通过值传递给函数。
TA贡献1815条经验 获得超13个赞
有几种情况需要考虑。
参数修改(“out”和“in / out”参数)
void modifies(T ¶m);// vsvoid modifies(T *param);
这种情况主要是关于样式的:你想让代码看起来像call(obj)还是call(&obj)?但是,有两点是重要的:下面是可选的情况,并且您希望在重载运算符时使用引用。
......和可选的
void modifies(T *param=0); // default value optional, too// vsvoid modifies();void modifies(T ¶m);
参数未修改
void uses(T const ¶m);// vsvoid uses(T param);
这是一个有趣的案例。经验法则是“便宜复制”类型是通过值传递的 - 这些通常是小类型(但并非总是) - 而其他类型则由const ref传递。但是,如果您需要在函数内复制,则应按值传递。(是的,这暴露了一些实现细节.C'est le C ++。)
......和可选的
void uses(T const *param=0); // default value optional, too// vsvoid uses();void uses(T const ¶m); // or optional(T param)
所有情况之间的差异最小,因此请选择最适合您生活的方式。
Const by value是一个实现细节
void f(T);void f(T const);
这些声明实际上是完全相同的功能! 当传递值时,const纯粹是一个实现细节。 试试看:
void f(int);void f(int const) { /* implements above function, not an overload */ }typedef void NC(int); // typedefing function typestypedef void C(int const);NC *nc = &f; // nc is a function pointerC *c = nc; // C and NC are identical types
- 4 回答
- 0 关注
- 790 浏览
添加回答
举报