2

I have a lot of C# Code that I have to write in C++. I don't have much experience in C++.

I am using Visual Studio 2012 to build. The project is an Static Library in C++ (not in C++/CLI).

I know this is a basic question, but I have been reading around, and I got rather confused. In the C# code they were using double[] arrays in several places, from the way they were using them, I saw the best way to replace them in C++ was using vector.

There are some properties in C# returning copies of the arrays, I want to do the same in C++.

Note: myArray is member of MyClass.

C#

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

I want to accomplish something similar in C++, but minimizing the amount of copies created. Would this be correct?

C++

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

I just want one copy of myArray to be created. Since I am not returning a reference, It is my understanding that when returning myCloneArray, a copy of it will be created. Is this always true?

I wanted to make sure, so I was reading on internet, but I am confused because some people says that some compilers don't do that.

I want to make sure I am always sending a copy, and not the same vector. I am working right now with a compiler, but ultimately my code will be build in other compilers as well, so I need to be sure this is not compiler-dependant

Is this the best way I can go? or could i reduce the code, like this:

C++

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

And the copy constructor of vector (myArray) will be called?

Dzyann
  • 5,062
  • 11
  • 63
  • 95
  • I think with optimizations like NRVO: http://stackoverflow.com/questions/3703302/c-vector-return-vs-parameter/3703325#3703325 you should hopefully be OK doing this kind of thing in most cases. (no extra manual copies in your code though! that could mess it up) –  Nov 07 '13 at 19:59

2 Answers2

5

You actually don't need to create myCloneArray. Just return myArray, and it will pass a copy. This is the case on EVERY compiler.

In general, if an object is being returned, and it is not being returned by reference or as a pointer, the copy constructor will be called on the class with your object passed as an argument. The only time this doesn't happen is if the copy constructor has been deleted, and in that case, the code you posted wouldn't compile anyways.

The reason this is different between C++ and say, C# or JAVA, is that in C# and JAVA, you are essentially returning a pointer, not copying (or moving) an object on the stack. If you think of it this way, the behaviors are identical between languages.

Jonathan Henson
  • 8,076
  • 3
  • 28
  • 52
  • Thanks for your quick answer! I was rather worried, I don't really know anyone that is good at C++ and I don't want to mess up. – Dzyann Nov 07 '13 at 19:58
  • ...unless we are in C++11 and myArray is a local variable - some compilers may invoke move ctor instead of copy ctor :) But if myArray is a class field, there's no way that compiler will move it instead of copying. – Spook Nov 07 '13 at 19:59
  • @Spook, but since myArray is not a local variable, it should be ok, no? – Dzyann Nov 07 '13 at 20:01
  • 1
    @Dzyann, you are fine. I can assure you. – Jonathan Henson Nov 07 '13 at 20:01
3

C++ differ from C# in terms of class allocation, because it allows automatic allocation of classes, while C# requires the classes to be instantiated explicitly every time.

When you write in C++:

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

There's an equivalent in C#:

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

But if you allocate the class automatically:

std::vector<int> vec;

There's no way you can simply translate it to C# (the language construct, I mean).

Classes allocated automatically behave more less the same as simple values. So - for example - when you pass a local variable by a parameter to a function, it is being passed by value - meaning, that its value is copied to function body. Similarly, when you pass class allocated automatically by a parameter to a function, it also will be copied to the class body.

The similar mechanism exists, when you return class instance from a function (by value, like in your case - not by pointer or reference). A copy of that class is being made and returned to the caller, such that original class remains unchanged (regardless of where and how it was allocated).

There's a catch in C++11 though. People, who work on C++ standard saw, that if you produce a vector with, say, 1000 elements and then return it from the function, these 1000 elements have to be copied to another vector, which will be returned from the function, and then the original vector is being destroyed. That's a huge unnecessary performance loss.

That's why they introduced a move constructor. In the described case the constructor of the copy, which is being returned from the function does not copy the elements, but just moves some fields from the local variable to get access to these elements (like an array pointer). The local variable is destroyed immediately after, so there's no problem and only one pointer is copied - not 1000 elements.

This situation can occur in modern C++ compilers, but only if compiler is absolutely sure, that the vector from which data are being copied won't be used anymore. So if you are returning a vector, which is a class field, there's no way compiler will call a move ctor.

Now, after a bit of theory, let's look at your code.

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

First, you prepare myArray. Then, in (1) statement, you:

  • Explicitly create a temporary copy of that array by calling vector<double>(myArray);
  • Then, you copy contents of that temporary copy to myCloneArray
  • Then you return myCloneArray and it is being copied again, to the result, which is returned from the function.

If myArray is a class field, you can as well do it a lot simpler:

vector<double> MyClass::GetMyArray()
{   
    return myArray;
}
Spook
  • 25,318
  • 18
  • 90
  • 167
  • Following your explanation about C++11, If I understood correctly, myCloneArray would be "cloned", but by using the move constructor? (that in a compiler working with C++11) – Dzyann Nov 07 '13 at 20:17
  • @Dzyann Simply, your vector will always be copied by return (of a value) automatically. The complicated part is just that sometimes the compiler will optimize out individual copies when it realizes the original is about to be destroyed anyways. You're always safe knowing you won't modify the original, but sometimes the performance will be as good as a pointer (reference) copy. –  Nov 07 '13 at 20:42
  • @ebyrob, yes, I was just trying to verify that I understood the move copy correctly. In my code the myCloneArray is a local variable, so if I understood correctly, according to what Spook said, the move constructor will be called when i return myCloneArray. – Dzyann Nov 07 '13 at 20:56
  • 1
    @Dzyann In short words, if compiler is **absolutely sure**, that the original vector won't be used anymore, it may move it instead of copying. If there's a slightest chance, that it may be used afterwards (such as in your example, assuming, that myArray is a class field), it will **always** copy it. – Spook Nov 08 '13 at 06:42