2

我有很多必须用 C++ 编写的 C# 代码。我在 C++ 方面没有太多经验。

我正在使用Visual Studio 2012进行构建。该项目是 C++ 中的静态库(不在 C++/CLI 中)。

我知道这是一个基本问题,但我一直在阅读,我很困惑。在 C# 代码中,他们在几个地方使用了double[] 数组,从他们使用它们的方式来看,我看到在 C++ 中替换它们的最佳方法是使用向量。

C# 中有一些属性返回数组的副本,我想在 C++ 中做同样的事情。

注意:myArray 是 MyClass 的成员。

C#

public double[] MyArray
    {
        get
        {
            /*** Some Code Here ***/
            double[] myCloneArray= (double[])myArray.Clone();
            return myCloneArray;
        }
    }

我想在 C++ 中完成类似的事情,但尽量减少创建的副本数量。这是正确的吗?

C++

vector<double> MyClass::GetMyArray()
{   
      /*** Some Code Here ***/
      vector<double> myCloneArray= vector<double>(myArray);
      return myCloneArray;  
}

我只想创建一个 myArray 的副本。由于我没有返回引用,因此我的理解是在返回 myCloneArray 时,将创建它的副本。这总是正确的吗?

我想确定一下,所以我在网上阅读,但我很困惑,因为有些人说有些编译器不这样做。

我想确保我总是发送一个副本,而不是同一个向量。我现在正在使用编译器,但最终我的代码也将在其他编译器中构建,所以我需要确保这不依赖于编译器

这是我能走的最好的方式吗?或者我可以减少代码,如下所示:

C++

vector<double> MyClass::GetMyArray()
{   
      /*** Some Code Here ***/
      return myArray;   
}

并且会调用vector(myArray)的复制构造函数?

4

2 回答 2

5

您实际上不需要创建 myCloneArray。只需返回 myArray,它就会传递一个副本。每个编译器都是这种情况。

通常,如果一个对象被返回,并且它不是通过引用或作为指针返回的,则将在类上调用复制构造函数,并将您的对象作为参数传递。唯一不会发生这种情况的是复制构造函数已被删除,在这种情况下,您发布的代码无论如何都不会编译。

这在 C++ 和 C# 或 JAVA 之间有所不同的原因在于,在 C# 和 JAVA 中,您实际上是在返回一个指针,而不是在堆栈上复制(或移动)一个对象。如果你这样想,语言之间的行为是相同的。

于 2013-11-07T19:57:20.580 回答
3

C++ 在类分配方面与 C# 不同,因为它允许自动分配类,而 C# 要求每次都显式实例化类。

当你用 C++ 编写时:

std::vector<int> * vec = new std::vector<int>();

在 C# 中有一个等价物:

List<int> list = new List<int>;

但是如果你自动分配类:

std::vector<int> vec;

您无法简单地将其翻译为 C#(我的意思是语言结构)。

自动分配的类的行为与简单值不同。因此 - 例如 - 当您通过参数将局部变量传递给函数时,它是按值传递的 - 这意味着它的值被复制到函数体。同样,当您将参数自动分配的类传递给函数时,它也会被复制到类体中。

当您从函数返回类实例时,存在类似的机制(按值,如您的情况 - 而不是通过指针或引用)。正在制作该类的副本并将其返回给调用者,以使原始类保持不变(无论分配的位置和方式如何)。

不过,C++11 有一个问题。从事 C++ 标准工作的人看到,如果你生成一个包含 1000 个元素的向量,然后从函数中返回它,那么这 1000 个元素必须复制到另一个向量,该向量将从函数返回,然后原始向量正在被破坏。这是一个巨大的不必要的性能损失。

这就是他们引入移动构造函数的原因。在所描述的情况下,从函数返回的副本的构造函数不会复制元素,而只是从局部变量中移动一些字段以访问这些元素(如数组指针)。局部变量在之后立即被销毁,所以没有问题,只复制了一个指针 - 而不是 1000 个元素。

这种情况可能发生在现代 C++ 编译器中,但前提是编译器绝对确定将不再使用从中复制数据的向量。因此,如果您要返回一个向量,它是一个类字段,编译器将无法调用移动 ctor。

现在,经过一些理论,让我们看看你的代码。

vector<double> MyClass::GetMyArray()
{   
    vector<double> myCloneArray= vector<double>(myArray); // 1
    return myCloneArray; // 2
}

首先,您准备 myArray。然后,在 (1) 语句中,您:

  • 通过调用显式创建该数组的临时副本vector<double>(myArray)
  • 然后,将该临时副本的内容复制到 myCloneArray
  • 然后你返回 myCloneArray 并且它被再次复制到从函数返回的结果中。

如果 myArray 是一个类字段,你也可以简单得多:

vector<double> MyClass::GetMyArray()
{   
    return myArray;
}
于 2013-11-07T20:12:34.647 回答