返回 C++ 等效于 c# 的矢量

Returning Vector in C++ equivalent to c#

本文关键字:C++ 返回      更新时间:2023-10-16

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

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

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

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;   
}

并且向量(myArray)的复制构造函数将被调用?

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

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

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

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;
}