这是通过引用还是通过值传递?

时间:2012-03-01 21:46:14

标签: c++ pass-by-reference pass-by-value

假设我有以下内容:

class MyClass
{
    // ...
}

void doSomething (MyClass instance)
{
    // Is instance passed by reference or by value (copied)?
}

void main ()
{
    MyClass instance = MyClass();

    doSomething(instance);
}

doSomething() instance是否通过引用传递?或者类是否在内存中重复?或其他什么?

4 个答案:

答案 0 :(得分:5)

这是通过值传递的

void doSomething (MyClass instance)

这是通过引用传递的

void doSomething (MyClass& instance)

这是由const引用传递的

void doSomething (const MyClass& instance)

同样MyClass不需要通过赋值构造。 所以:

MyClass mc=MyClass();

实际上与:

相同
MyClass mc; //no parens needed for default constructor (no args).

编辑: 这是通过const引用传递给const函数,const函数可以在const对象上调用,因为它保证不修改对象状态。

void doSomething (const MyClass& instance) const

与许多不太严格的语言不同,Const正确性被认为是C ++中的良好实践。

见我:

http://en.wikipedia.org/wiki/Const-correctness

http://www.gotw.ca/gotw/006.htm

答案 1 :(得分:1)

如果没有明确说明,则不是参考。这是有价值的。

以下原型表示通过引用传递的参数:

void doSomething (MyClass& instance)
{
    // Is instance passed by reference or by value (copied)?
    // In this case, by reference
}

实际上,在您的情况下,很可能会创建一个新对象。我说的最有可能的原因是,只要可观察的行为是相同的,它也可能不是。但是,理论上,是的,创建了一个在函数内部使用的新对象。

通过调用作为参数传递的对象的复制构造函数来创建新对象。如果尚未定义复制构造函数,则编译器会生成一个默认值,它会执行浅表复制。

答案 2 :(得分:1)

是的,它被复制了。

当您致电doSomething时,会调用MyClass复制构造函数来创建新实例。

此实例将在doSomething函数的持续时间内保留。当函数结束时,将为此实例调用MyClass析构函数。

(请注意,如果您还没有编写复制构造函数,默认情况下会为您创建一个。)

因此,如果添加显式复制构造函数和析构函数:

class MyClass
{
    public:
         MyClass()
         {
             std::cout << "MyClass constructor" << std::endl;
         }
         MyClass(const MyClass& other)
         {
               std::cout << "MyClass copy constructor" << std::endl;
         }
         MyClass::~MyClass()
         {
               std::cout << "MyClass destructor" << std::endl;
         }
}
void doSomething (MyClass instance)
{
    std::cout << "doSomething method";
}

void main ()
{
    MyClass instance = MyClass();
    std::cout << "invoking doSomething" << std::endl;
    doSomething(instance);
    std::cout << "returned from doSomething" << std::endl;
}

这将输出以下内容:

  • MyClass构造函数
  • 调用doSomething
  • MyClass复制构造函数
  • doSomething方法
  • MyClass析构函数
  • 从doSomething返回
  • MyClass析构函数

答案 3 :(得分:1)

它被复制在堆栈上以便传递给函数。如果您的类已达到一定量的字节,这可能非常昂贵,因为每个实例变量必须在堆栈上布局。在这种情况下,类的行为与常规c结构的行为不同。

所以假设你在课堂上有2个整数(我假设是32位系统)

class A {
    int a;
    int b;
};

当你在main中声明它时,堆栈指针会下降8个字节。 如果您调用your_function(A),C也必须将布局类复制到堆栈中,以便your_function在调用后可以访问它。这意味着堆栈指针再次下降8个字节,值从旧值写入并调用函数。

有2个实例变量,这不是什么大问题。但是图像你有一个持有结构的类,可以说20个整数+一个虚拟表?比我可以是一个非常昂贵的操作。如果通过指针传递,则堆栈指针必须仅下降4个字节,复制其中的类的地址并调用该函数。当然更便宜。

你可以自己尝试。只需更改函数中的某个实例变量,然后在函数返回后检查,如果第一个类具有新值或函数调用之前的值。这应该给你答案。

在任何情况下,如果这是您想要的,您应该实现一个复制构造函数来处理如何复制变量。