edmqkk
edmqkk

Reputation: 356

Is there a way to rewrite a function that returns a pointer to an istringstream to instead return a reference?

Here's my code that works:

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

istringstream* get_line() {
  string line;
  getline(cin, line);
  return new istringstream(line);
}

int main() {
  istringstream* line = get_line();
  int number_of_arrays, number_of_queries;
  *line >> number_of_arrays >> number_of_queries;

  int sum = number_of_arrays + number_of_queries;
  vector<int> vectors[sum];

  for (int i = 0; i < sum; ++i) {
    line = get_line();
    int n;
    while (*line >> n) vectors[i].push_back(n);
    delete line;
  }

  cout << endl;
  for (int i = number_of_arrays; i < sum; ++i) {
    int vector = vectors[i][0];
    int index = vectors[i][1];
    cout << vectors[vector][index] << endl;
  }
  return 0;
}

Here are some of my attempts to use references instead:

Attempt 1:

istringstream& get_line() {
  string line;
  getline(cin, line);
  return new istringstream(line);
}
...
istringstream& line = get_line();

Error:

x.cpp: In function ‘std::istringstream& get_line()’:
x.cpp:10:32: error: invalid initialization of non-const reference of type ‘std::istringstream& {aka std::__cxx11::basic_istringstream<char>&}’ from an rvalue of type ‘std::istringstream* {aka std::__cxx11::basic_istringstream<char>*}’
   return new istringstream(line);
                            ^
x.cpp: In function ‘int main()’:
x.cpp:23:12: error: type ‘std::istringstream {aka class std::__cxx11::basic_istringstream<char>}’ argument given to ‘delete’, expected pointer
     delete line;

Attempt 2:

const istringstream& get_line() {
  string line;
  getline(cin, line);
  const istringstream* is = new istringstream(line);
  return is;
}
...
istringstream& line = get_line();

Error:

x.cpp: In function ‘const istringstream& get_line()’:
x.cpp:11:10: error: invalid initialization of reference of type ‘const istringstream& {aka const std::__cxx11::basic_istringstream<char>&}’ from expression of type ‘const istringstream* {aka const std::__cxx11::basic_istringstream<char>*}’
   return is;
          ^
x.cpp: In function ‘int main()’:
x.cpp:21:35: error: binding ‘const istringstream {aka const std::__cxx11::basic_istringstream<char>}’ to reference of type ‘std::istringstream& {aka std::__cxx11::basic_istringstream<char>&}’ discards qualifiers
     istringstream& line = get_line();
                                   ^
x.cpp:24:12: error: type ‘std::istringstream {aka class std::__cxx11::basic_istringstream<char>}’ argument given to ‘delete’, expected pointer
     delete line;
            ^

What the code is doing:

This is a variation on a coding site puzzle:

input:

2 3 // after this line i will specify 2 arrays and 3 queries

1 2 3 4 5 // array 0

6 7 8 // array 1

0 3 // query (return element at index 3 for array 0)

1 1 // query (return element at index 1 for array 1)

1 2 // etc

output:

4

7

8

Upvotes: 0

Views: 95

Answers (1)

Ted Lyngmo
Ted Lyngmo

Reputation: 117433

Return by value, example:

#include <iostream>
#include <sstream>

std::istringstream get_line() {
    std::cout << "enter: ";
    std::string line;
    std::getline(std::cin, line);
    std::istringstream rv(line);
    // set the state of the stringstream to whatever state std::cin is in to
    // be able to detect EOF or error conditions outside this function
    rv.setstate(std::cin.rdstate());
    return rv;
}

int main() {
    std::istringstream ss;

    while(ss = get_line()) { // loop while the state is good
        std::string a;
        while(ss >> a) { // extract
            std::cout << a << "\n";
        }
    }
}

You could also dereference the pointer you get from new to return a reference from your function - but it'd be utterly confusing since the responsibility to delete the stringstream would not be obvious to anyone using that function. One would need to delete &line; in that case. Don't do this:

#include <iostream>
#include <sstream>

std::istringstream& get_line() {
    std::cout << "enter: ";
    std::string line;
    std::getline(std::cin, line);
    std::istringstream* rv = new std::istringstream(line);
    // set the state of the stringstream to whatever state std::cin is in
    rv->setstate(std::cin.rdstate());
    return *rv; // dereference
}

int main() {
    std::istringstream& line = get_line();
    std::string a;
    while(line>> a) { // extract
        std::cout << a << "\n";
    }
    delete &line;
}

Upvotes: 2

Related Questions