1

I am a C++ beginner ( came from Java ). I have the following code:

//#include <boost/algorithm/string.hpp>
#include <iostream>
#include <math.h>
#include <vector>
#include <string.h>
#include <string>
#include <bitset>
#include <algorithm>
#include <sstream>
#include <memory>
#include <assert.h>
#include <cctype>

using namespace std;

class Point{
private:
    int x;
    int y;
public:
    Point(int x,int y){
        this->x=x;
        this->y=y;
    }

    int getX(){
        return x;
    }

    int getY(){
        return y;
    }

    operator const char*(){
        return toString().c_str();
    }

    string toString(){
        ostringstream stream;
        stream<<"( "<<x<<", "<<y<<" )";
        return stream.str();
    }
};


class Line{
private:
    Point p1=Point(0,0);
    Point p2=Point(0,0);

public:
    Line(Point p1, Point p2){
        this->p1=p1;
        this->p2=p2;
    }

    Point getP1(){
        return p1;
    }

    Point getP2(){
        return p2;
    }

    operator const char*(){
        ostringstream stream;
        stream<<"[ "<<p1<<" -> "<<p2<<" ]";
        return stream.str().c_str();
    }

    //    operator const char*(){
    //        ostringstream stream;
    //        stream<<"[ "<<p1<<" -> ";
    //        stream<<p2<<" ]";
    //        return stream.str().c_str();
    //    }
};

int main()
{

    Line line=Line(Point(1,2), Point(3,4));
    cout<<line<<endl;


    cout<<"\nProgram exited successfully."<<endl;
    return 0;
}

I have redefined the operator const* so that I can use cout<

But, If I run the program as it is now, with the second block commented out ( I have 2 versions of operator const*, and by default the second one is commented out ) ,it will display

[ (1, 2) -> (1, 2) ]

But when running with the second block uncommented, the output is as expected:

[ (1, 2) -> (3, 4) ]

The issue seems to occur when I display both Point objects in the same line ( some kind of chaining, though I don't know if chaining is the right word here )

My question, is,why is this happening?

UPDATE

I have added the std::ostream& operator << function to my Line class but now I'm receiving the following errors:

/home/ryu/qt_workspace/hello/main.cpp:67: error: 'std::ostream& Line::operator<<(std::ostream&, const Line&)' must take exactly one argument

/home/ryu/qt_workspace/hello/main.cpp:77: error: cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'

Regards, Aurelian

aureliangtx
  • 317
  • 6
  • 18
  • 2
    The proper way to provide printing functionality is to overload `operator<<`. Also, you're returning a pointer to memory that is no longer valid. – chris Jun 03 '13 at 20:04
  • Can you elaborate please, regarding the invalid pointer? Are you referring to the fact that since ostringstream is a local variable, and from it I call str and then c_str, the pointers are also destroyed when the declaring method ends? Is there a way to know if a method uses pointers allocated dinamically or statically? Also, why doesn't the program crash, or print strange characters if the pointer is invalid? Kind regards, Aurelian – aureliangtx Jun 03 '13 at 20:50
  • 1
    You call `str()`, which creates a `std::string`, then call `c_str()` on that and return the resulting pointer, which points to that temporary string, destroyed at the end of the full expression. It doesn't crash or anything because it's undefined behaviour. It can do anything. – chris Jun 03 '13 at 20:56
  • Regarding your update - it sounds like you forgot the `friend` keyword from my answer. – Drew Dormann Jun 03 '13 at 22:38
  • Hi Drew, sorry for late answer, I tried adding friend keyword but I receive /home/ryu/qt_workspace/hello/main.cpp:81: error: cannot bind 'std::basic_ostream' lvalue to 'std::basic_ostream&&' Thanks for all – aureliangtx Jun 04 '13 at 17:47

2 Answers2

2

If you want to use cout <<, there is a more direct way to do that.

Add this function to Line.

friend std::ostream& operator << ( std::ostream & os, const Line & l ){
    os << "[ " << l.p1 << " -> " << l.p2 << " ]";
    return os;
}

You should also note that your approach was returning invalid memory - this is a significant way that Java differs from C++.

    return stream.str().c_str();  // Danger!

stream was declared in operator const char*() which limits its lifetime to that function. It is destroyed when that scope is exited. As a result, you are returning a pointer to something that no longer exists.

Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
  • Rather, the string returned by `str()` is. Even going `auto str = stream.str().c_str();` leaves `str` being a dangling pointer. – chris Jun 03 '13 at 20:14
0

actually I think with C++11 returning the string by value is perfectly fine, so you can do the transfer there instead of using the cstring underneath.

What are move semantics?

Community
  • 1
  • 1