Ngjing Jie
Ngjing Jie

Reputation: 11

is there another way to do use stringstream?

I am currently using stringstream to pass a string over but I was wondering if there is another way of doing it? below is a snip shot of how it's done. as I am still quite new to c++, I am not sure if this is the best way to do it or there could be an alternative as I heard using string stream slows down the process and was hoping to learn more.

string Circle::toString()
{
   stringstream sentence;
   sentence << "Shape [" << index <<"]" << endl;
   sentence << "Name: " << name << endl;

   if (containsWarpSpace == false)
       sentence << "Special Type: NS" << endl;
   else
       sentence << "Special Type: WS" << endl;

   sentence << "Area: " << area << " units square" << endl;
   sentence << "Vertices: " << endl;
   sentence << "Point[0]: (" << center[0] << ", " << center[1] << ")" << endl;
   sentence << endl;
   sentence << "Points on perimeter: " << endl;
   bool trueFalse= false;
   int count = 0;
   for ( int y = center[1] - unit; y < center[1] + unit + 1; y++)
   {
      for ( int x = center[0] - unit; x < center[0] + unit + 1; x++)
      {
         trueFalse = isPointOnShape (x, y);
         if (trueFalse == true)
         {
            if (count %6 == 0)
                sentence << "(" << x << ", " << y << ")";
            else
                sentence << ", (" << x << ", " << y << ")";

            count++;
            if (count %6 == 0)
                sentence << endl;
         }
      }
   }

   if (count == 0)
       sentence << "none!";

   sentence << endl;
   count = 0;
   sentence << "Points within shape: " << endl;
   for (int y = center[1] - unit; y < center[1] + unit + 1; y++)
   {
      for ( int x = center[0] - unit; x < center[0] + unit + 1; x++)
      {
         trueFalse = isPointInShape (x, y);

         if (trueFalse == true)
         {
            if (count %6 == 0)
                sentence << "(" << x << ", " << y << ")";
            else
                sentence << ", (" << x << ", " << y << ")";

            count++;
            if (count %6 == 0)
                sentence << endl;
         }
      }
   }
   if (count == 0)
       sentence << "none!";

   sentence << endl;    
   return sentence.str();
} 

hope some one could guide me on this

Upvotes: 1

Views: 243

Answers (1)

PooSH
PooSH

Reputation: 701

The way you are using stringstream is fine, but you need to consider that your code creates a stringstream object in every toString() call, which, in turn, leads to memory allocation. For example, if you have a thousand circles to dump into a string, then there will be a thousand memory allocations for the underlying memory buffer of a temporary stringstream object, eventually following by a thousand deallocations (and maybe reallocations if the initial buffer isn't big enough).

Most likely, you will be using toString() for debugging or logging, where performance doesn't matter that much. However, there is room for improvement. Think about what you're going to do with the string returned by Circle::toString()? Most likely, the string is going to be displayed, written to a file, or maybe streamed via a network. You'll be doing something like cout << circle.toString(). Instead of creating a temporary stringstream object, converting it into a temporary string, and finally writing it into a stream, you can write it into the output stream directly.

void Circle::toStream(ostream &os)
{
    os << "Shape [" << index <<"]\n";
    // ...
    os << endl;
}

In the header file declare operator<<. That allows you writing cout << circle;

class Circle {
    // ...
public:
    void toStream(ostream &os);

    friend ostream & operator << (ostream &os, const Circle &c) {
        c.toStream(os);
        return os;
    }
};

If Circle has a base class, then it is a good idea to declare toStream as virtual on the base level:

class Object {
public:
    virtual ~Object() = default;

    virtual void toStream(ostream &os) = 0;

    friend ostream &operator << (ostream &os, const Object &obj) {
        obj.toStream(os);
        return os;
    }    
};

class Circle : public Object {
public:
    void toStream(ostream &os) override;
};

class Rectangle : public Object {
public:
    void toStream(ostream &os) override;
};

Now you can print any object to any output stream without performance drawback while still keeping your code clean.

Circle circle1, circle2;
Rectangle rectangle;
// ...
// print circle to stdout
cout << "My circles:\n" << circle1 << circle2;
cout << "My rectangle:\n" << rectangle;
// write circles to a file
ofstream myfile;
myfile.open ("circle.log");
myfile << circle1 << circle2;
myfile.close();

Finally, if you need a string after all, then you can create a helper method:

string Circle::toString()
{
    stringstream sentence;
    toStream(sentence);
    return sentence.str();
}

Upvotes: 1

Related Questions