0

Bellow is a simple program that works fine. It contains a function that is able to return a string of arbitrary size. The size of which is determined by the function input.

#include <iostream>                                                                                                                                                                                                                           
                                                                                                                                                                                                                                              
using namespace std;                                                                                                                                                                                                                          
                                                                                                                                                                                                                                              
string strFunc(int a){                                                                                                                                                                                                                        
                                                                                                                                                                                                                                              
  string toBeReturned;                                                                                                                                                                                                                        
                                                                                                                                                                                                                                              
  for(int i=0; i < a; i++){                                                                                                                                                                                                                   
    toBeReturned += '!';                                                                                                                                                                                                                      
  }                                                                                                                                                                                                                                           
  return toBeReturned;                                                                                                                                                                                                                        
}                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                              
                                                                                                                                                                                                                                              
int main(){                                                                                                                                                                                                                                   
                                                                                                                                                                                                                                              
  int x = 5;                                                                                                                                                                                                                                  
                                                                                                                                                                                                                                              
  cout << strFunc(x) << endl;                                                                                                                                                                                                                 
                                                                                                                                                                                                                                              
  return 0;                                                                                                                                                                                                                                   
}             

                                                                                                                                                                                                                            

If instead I wanted a function (or a single process to call in main) to return a 1-D array (int toBeReturned[size to be determined]) I had to use a function that returns a pointer and then include that function in a macro that constructs the array.

Is there a simpler way of doing this in c++?

If not can someone please explain why this only works for type string? I thought that a string is simply a 1-D array of type 'char'.

Thank you,

Daniel

  • 1
    _I thought that a string is simply a 1-D array of type 'char'._ The `std::string` is a class that has members to keep track of the string length. Raw `char` arrays do not. C-style "strings" use the sentinel character `\0` to mark the end of the string but the array can be bigger. – 001 Dec 23 '21 at 21:37
  • " I had to use a function that returns a pointer and then include that function in a macro that constructs the array." its not clear what you mean by that. A macro cannot do what you couldnt do also without – 463035818_is_not_an_ai Dec 23 '21 at 21:38
  • I understand you're not after something like `std::vector(x)` for creating a vector of `x` elements of type `T`. – rturrado Dec 23 '21 at 21:49

2 Answers2

3

A function can return any POD or class type by value.

A C++-style std::array is a fixed-sized array wrapped in a class type, and thus can be returned by value. However, a C-style fixed-sized array cannot be returned by value (but it can be stored as a member of a class type, which can then be returned by value, like std::array does).

A C-style array can't be sized dynamically (without using a non-standard compiler extension), which is why you would have to new[] it, return it by pointer, and then delete[] it when you are done using it.

Since you want your function to return a dynamic-sized array, you should use std::vector instead of a new[]'ed pointer, eg:

#include <iostream>                                                                                                                                                                                                                           
#include <vector>                                                                                                                                                                                                                                        
using namespace std;                                                                                                                                                                                                                          

vector<int> strFunc(int a){                                                                                                                                                                                                                        

  vector<int> toBeReturned(a); 

  for(size_t i = 0; i < a; ++i){
    toBeReturned[i] = ...;                                                                                                                                                                                                                      
  }

  return toBeReturned;
}                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                              
int main(){                                                                                                                                                                                                                                   
                                                                                                                                                                                                                                              
  int x = 5;
                                                                                                                                                                                                                                              
  vector<int> returned = strFunc(x);
  for(size_t i = 0; i < x; ++i){
    cout << returned[i] << ' ' << endl;
  }
                                                                                                                                                                                                                                              
  return 0;                                                                                                                                                                                                                                   
} 
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
2

You can use a vector of whatever type you need, and pass it into your function by reference.

#include <vector>
#include <chrono>
#include <iostream>
using namespace std;



void by_reference(vector<size_t>& v, size_t s)
{
    v.clear();
    v.resize(s, 0);

    for (size_t i = 0; i < s; i++)
        v[i] = i;
}

vector<size_t> by_return(size_t s)
{
    vector<size_t> v(s, 0);

    for (size_t i = 0; i < s; i++)
        v[i] = i;

    return v;
}



// Where s is large, by_reference is faster
// Where s is small, by_return is faster
// Use whichever works best for you and your situation



int main(void)
{
    std::chrono::high_resolution_clock::time_point start_time, end_time;
    std::chrono::duration<float, std::milli> elapsed;

    start_time = std::chrono::high_resolution_clock::now();

    for (size_t i = 0; i < 1000; i++)
    {
        vector<size_t> v;

        const size_t s = 10000000;

        by_reference(v, s);

        for (size_t i = 0; i < s; i++)
            v[i] = i;
    }

    end_time = std::chrono::high_resolution_clock::now();

    elapsed = end_time - start_time;

    cout << "Duration: " << elapsed.count() / 1000.0f << " seconds" << endl;



    start_time = std::chrono::high_resolution_clock::now();

    for (size_t i = 0; i < 1000; i++)
    {
        const size_t s = 10000000;

        vector<size_t> v = by_return(s);

        for (size_t i = 0; i < s; i++)
            v[i] = i;
    }

    end_time = std::chrono::high_resolution_clock::now();

    elapsed = end_time - start_time;

    cout << "Duration: " << elapsed.count() / 1000.0f << " seconds" << endl;

    return 0;
}
shawn_halayka
  • 96
  • 1
  • 1
  • 9
  • 1
    What do your timings actually show? What C++ version are you compiling with? `by_return()` should be just as fast as `by_reference()` when (N)RVO/copy-elison is used. – Remy Lebeau Dec 25 '21 at 20:12
  • It says in the source code that by reference is slower where the vector .size() is small (like 1000), and that by reference is faster where .size() is large (like 10,000,000). It depends on the usage. I’m using Microsoft Visual C++ 2019 with optimizations enabled, of course. – shawn_halayka Dec 25 '21 at 20:26
  • There are also RAM considerations. Does returning a vector double the amount of RAM used, if only briefly? That kind of sucks when you only have 8GB of RAM to play with. – shawn_halayka Dec 25 '21 at 20:50
  • 2019 is a VS compiler version, not a C++ language version. Which C++ are you compiling for? C++11, C++14, C++17, C++20? Again, what you describe is not an issue when [copy elison](https://en.cppreference.com/w/cpp/language/copy_elision) is used. The compiler can optimize away the function's local variable being `return`'ed so that the function operates directly on caller's receiving variable instead, thus avoiding an unnecessary copy/move. – Remy Lebeau Dec 25 '21 at 20:57