Live data from Hacker News

Returning multiple values from functions in C++

eli.thegreenplace.net

1–10 of 67 posts

Re: Returning multiple values from functions in C++

#3

The getline case (boolean and possible value) really wants a type like Haskell's "Maybe" or Rust's Option: a type that either contains nothing or a value.

There's std::optional that's still in the works:

http://en.cppreference.com/w/cpp/experimental/optional

Re: Returning multiple values from functions in C++

#4

The getline case (boolean and possible value) really wants a type like Haskell's "Maybe" or Rust's Option: a type that either contains nothing or a value.

Unfortunately the currently available solution (boost::optional) performs enough worse that the difference can be measured in a simple implementation of "wc -l". Consider the following code:

    #include 
    #include 
    #include 

    using namespace std;
    using namespace boost;

    optional getline_(istream &st) {
        std::string line;
        if(getline(st, line)) return line;
        return none;
    }

    int main() {
        int lines = 0;
        while(getline_(cin)) lines++;
        cout 
vs

    using namespace std;
    int main() {
        int lines = 0;
        string line;
        while(getline(cin, line)) lines++;
        cout 
Run on an input file of 172,544 lines (the GPL-3 license repeated 256 times), the version using "optional" takes 400ms and performs 1,077,504(!) heap allocations, while the more standard version takes just 280ms and performs just 8 allocations.

Of course, "wc -l" (GNU) takes just 9ms, so clearly this isn't a great program either way--but it does serve to show that boost::optional can be a surprising performance sink compared to using a bool return value + out parameter.

(tests on debian jessie amd64, i5-3320M @ 2.6GHz, g++ 4.9 -O3, boost 1.55.0.2)

Re: Returning multiple values from functions in C++

#5
post #4

The getline case (boolean and possible value) really wants a type like Haskell's "Maybe" or Rust's Option: a type that either contains nothing or a value.

Unfortunately the currently available solution (boost::optional) performs enough worse that the difference can be measured in a simple implementation of "wc -l". Consider the following code: #include #include #include using namespace std; using namespace boost; optional getline_(istream &st) { std::string line; if(getline(st, line)) return line; return none; } int main() { int lines = 0; while(getline_(cin)) lines++;…

+1 for Having Measured It.

The basic getline interface removes heap pressure by reusing the same string over and over, even though semantically the optional approach may look cleaner. Eric Niebler showed a while ago (I can't remember where) that this API lends itself perfectly to ranges, and can provide both a reasonable interface without sacrificing performance. IIRC, the API looked somewhat like this:

    for (auto& line : getline_range(cin))
      f(line); // do something with line, e.g., parse.
The semantics are: iterate over standard input until EOF or error and let the range keep (and reuse) the string internally while exposing it as const-reference by dereferencing.

Re: Returning multiple values from functions in C++

#6
I know it's mentioned specially in the article but the C programmer in me immediately wants to use structs. They don't need to be complex or long lived or even initialized. And as a bonus there's no heap involved anywhere. Either that or just bail out of c++ and use go.

Re: Returning multiple values from functions in C++

#7
Instead of markers, I like to use typedefs instead. Here's an example how this would look like in a HPC related program. Basically, if you know Fortran, you know where this is coming from.

    typedef const double * const __restrict__ IN;
    typedef double * const __restrict__ OUT;
    typedef const int INT_VALUE;
    typedef const double FP_VALUE;

    void diffuse_c(
        OUT runtime_total_s,
        OUT runtime_boundary_s,
        OUT thermal_energy_updated,
        IN thermal_energy,
        INT_VALUE nx,
        INT_VALUE ny,
        INT_VALUE nz
    );

Re: Returning multiple values from functions in C++

#8
post #4

The getline case (boolean and possible value) really wants a type like Haskell's "Maybe" or Rust's Option: a type that either contains nothing or a value.

Unfortunately the currently available solution (boost::optional) performs enough worse that the difference can be measured in a simple implementation of "wc -l". Consider the following code: #include #include #include using namespace std; using namespace boost; optional getline_(istream &st) { std::string line; if(getline(st, line)) return line; return none; } int main() { int lines = 0; while(getline_(cin)) lines++;…

That's not the fault of optional though. It's because with the optional version you're creating (and destroying) a new string each iteration of the loop.

Something like this (untested) should be much closer to the non-optional version:

    #include 
    #include 
    #include 

    using namespace std;
    using namespace boost;

    optional getline_(istream &st, string& line) {
        if(getline(st, line)) return line;
        return none;
    }   

    int main() {
        int lines = 0;
        string line;
        line.reserve( 1024 );  //1024 should be long enough for any line
        while(getline_(cin, line )) lines++;
        cout 

Re: Returning multiple values from functions in C++

#9

I know it's mentioned specially in the article but the C programmer in me immediately wants to use structs. They don't need to be complex or long lived or even initialized. And as a bonus there's no heap involved anywhere. Either that or just bail out of c++ and use go.

std::tuple is essentially an "anonymous" struct -- there's no allocation involved
Post reply on HN