C ++中的默认传递引用语义

时间:2008-09-28 17:13:14

标签: c++ programming-languages syntax semantics

编辑:这个问题更多地是关于语言工程而不是C ++本身。我以C ++为例来展示我想要的东西,主要是因为我每天都在使用它。我不想知道它在C ++上是如何工作的,但是开始讨论如何

这不是它现在的工作方式,这就是我希望可以完成的方式,这肯定会打破C兼容性,但这就是我认为extern“C”的全部内容

我的意思是,在您现在声明的每个函数或方法中,您必须显式写入该对象将通过引用在其上添加前缀作为参考运算符。我希望每个非POD类型都会通过引用自动发送,因为我经常使用它,实际上对于每个大小超过32位的对象,这几乎是我的每一类。

让我们举例说明它是如何实现的,假设 a b c 为类:

class example {
    public:
        int just_use_a(const a &object);
        int use_and_mess_with_b(b &object);
        void do_nothing_on_c(c object);
};

现在我想要的是:

class example {
    public:
        int just_use_a(const a object);
        int use_and_mess_with_b(b object);
        extern "C" void do_nothing_on_c(c object);
};

现在,do_nothing_on_c()的行为就像今天一样。

至少对我来说这会很有趣,感觉更清楚,而且如果你知道每个非POD参数都是通过引用而来的,我相信如果你有错误将是相同的明确声明它。

对于这种变化的另一种观点,来自C的人,参考运算符在我看来是一种获取变量地址的方法,这就是我用来获取指针的方式。我的意思是,它是相同的运算符,但在不同的上下文中具有不同的语义,对你来说这不是有点不对吗?

9 个答案:

答案 0 :(得分:15)

答案 1 :(得分:10)

一个完全改变代码段意义的编译器选项对我来说听起来真的很糟糕。要么使用C ++语法,要么找到不同的语言。

答案 2 :(得分:2)

我宁愿不要通过将每个(非限定)参数作为参考来滥用引用。

引用加入C ++的主要原因是to support operator overloading;如果你想要“传递参考”语义,C有一个非常合理的方法:指针。

使用指针清楚地表明你想改变指向对象的值,并且可以通过查看函数调用来看到这一点,你不必查看函数声明来查看它是否正在使用参考

另外,请参阅

  

我确实想改变这个论点,   我应该使用指针还是应该使用   参考?我不知道强者   逻辑原因。如果通过``不是   对象''(例如空指针)是   可以接受,使用指针制作   感。我的个人风格是用一个   当我想修改一个指针   对象,因为在某些情况下   更容易发现一个   修改是可能的。

from the same FAQ

答案 3 :(得分:1)

老实说,我认为整个传递价值/通过C ++中的参考思想传递是误导。 Everything 是按值传递的。你有三种情况:

  1. 传递变量的本地副本

    void myFunct(int cantChangeMyValue)
    
  2. 将指针的本地副本传递给变量

    void myFunct(int* cantChangeMyAddress) {
        *cantChangeMyAddress = 10;
    }
    
  3. 你传递一个'引用'的地方,但是通过编译器魔法就像你传递一个指针一样,每次只是取消引用它。

    void myFunct(int & hereBeMagic) {
        hereBeMagic = 10; // same as 2, without the dereference
    }
    
  4. 我个人觉得很难记住,一切都是通过价值传递的。在某些情况下,该值可能是一个地址,允许您更改函数外部的内容。

    你的建议是不允许程序员做第1号。我个人认为拿掉那个选项是个坏主意。 C / C ++的一个主要优点是具有细粒度的内存管理。让一切都通过引用传递只是试图使C ++更像Java。

答案 4 :(得分:1)

是的,我认为这是一个非常令人困惑的超载。

这就是微软对这种情况所说的话:

  

不要将引用声明与使用address-of运算符混淆。当&标识符前面有一个类型,例如int或char,然后标识符被声明为对类型的引用。当&标识符前面没有类型,用法是address-of运算符。

我在C或C ++方面并不是很出色,但是我更加头疼,整理了*和&的各种用途。两种语言都比我在汇编程序中编码。

答案 5 :(得分:1)

最好的建议是养成思考你真正想要发生的事情的习惯。当你没有复制构造函数(或者不想使用它)时,通过引用传递是很好的,并且它对于大对象来说更便宜。然而,在课堂外感受到参数的突变。您可以通过const引用来传递 - 然后没有突变,但您无法进行本地修改。对于在函数中应该只读的廉价对象传递const by-value,并在需要可以进行本地修改的副本时传递非const by-value。

每个排列(按值/按引用和常量/非常量)具有明显不相等的重要差异。

答案 6 :(得分:1)

当您传递值时,您正在将数据复制到堆栈。如果您为要传递的结构或类定义了operator =,则会执行该操作。我所知道的没有编译器指令可以消除所提出的更改本身会导致的隐含语言混淆的严峻考验。

一个常见的最佳实践是通过const引用传递值,而不仅仅是通过引用传递值。这可确保在调用函数中无法更改该值。这是const-correct代码库的一个元素。

完全const-correct代码库更进一步,将const添加到原型的末尾。考虑一下:

void Foo::PrintStats( void ) const {
   /* Cannot modify Foo member variables */
}

void Foo::ChangeStats( void ) {
   /* Can modify foo member variables */
}

如果要将Foo对象传递给函数(以const为前缀),则可以调用PrintStats()。编译器在调用ChangeStats()时会出错。

void ManipulateFoo( const Foo &foo )
{
    foo.PrintStats();  // Works
    foo.ChangeStats(); // Oops; compile error
}

答案 7 :(得分:0)

有些事情不清楚。当你说:

  

int b(b& param);

你想要第二个'b'是什么意思?你忘记介绍一种类型吗?你是否忘了对第一个'b'做出不同的写作?难道你不觉得写下这样的东西很清楚:

class B{/*something...*/};
int b(B& param);

从现在开始,我想你的意思是我写的。

现在,你的问题是“难道你不认为编译器会将非POD的每个pass-by-value视为pass-by-ref会更好吗?”。 第一个问题是它会破坏你的合同。我想你的意思是传递CONST参考,而不仅仅是参考。

现在你的问题被简化为:“你知道是否有一些编译器指令可以按值优化函数调用?”

现在答案是“我不知道”。

答案 8 :(得分:0)

如果你开始混合所有可用的参数及其const变量,我认为c ++变得非常混乱。

它会迅速失控,无法进行所有复制构造函数调用,所有解除引用都会被重载等等。

相关问题