Murilo :P

C++, Computação, Programação, Web e afins :)

Feature turning into bug

with 2 comments

Team Phd na Área

Me and one of Unicamp teams

Background

A few days ago, after a sub-regional phase of ACM ICPC, one integrant of a team I’m coaching claimed that there was a bug in their C++ compiler. The team had to solve a geometrical problem, and, for that he implemented a class representing a point and an overload for operator*:

 

class point
{
 public:
     double x, y;

     point(double d) : x(d), y(d) {}
     point(const point& p) : x(p.x), y(p.y) {}     

     point operator*(const point& p)
     {
         // ...
         return result;
     }
};

After coding, he’ve compiled the code and tested with sample input tests. But the results were wrong. After some time debugging he found that the problem was happening because in some part of the code, he was calling point::operator* passing a double as argument and he didn’t implement that overload for operator*. The question was: why the compiler didn’t issued errors?

Implicit object construction

C++ has a feature which allow us to construct a object implicitly when the object’s type have a constructor which accepts one argument. For example, if you have a function which takes a std::string as argument, you can call that function passing a c-style string:

void printstr(std::string s)
{
    std::cout << s << std::endl;
}

// ...

printstr("Foo bar baz"); // Implicitly passes std::string("Foo bar baz");

The Google C++ Style Guide states:

Normally, if a constructor takes one argument, it can be used as a conversion. For instance, if you define Foo::Foo(string name) and then pass a string to a function that expects a Foo, the constructor will be called to convert the string into a Foo and will pass the Foo to your function for you.

So, what happened on the contestant program was something like:

point pt;
double d;

// ...

pt = pt * d; // doesn't find an operator* receiving a double
             // so, it is evaluated as pt = pt * point(d);

This feature can lead in many undesired conversions, so it is recommended to “turn off” this type of object construction by declaring constructors with one single argument explicit. The Google C++ Style Guide requires that all single argument constructors to be explicit, except in cases in which the class is a transparent wrapper for other class.

So, the modified code would be something like:

class point
{
 public:
     double x, y;

     explicit point(double d) : x(d), y(d) {}
     point(const point& p) : x(p.x), y(p.y) {}     

     // ...  
};

Some Links

About these ads

Written by Murilo Adriano

18 de September de 2012 at 19:11

2 Responses

Subscribe to comments with RSS.

  1. It was me. I spent more than 30 minutes debugging until I finally noticed this awesome “feature”!

    Actually, my constructor used default parameters, so it was even harder to spot the single argument constructor. It was something like this:

    point (double x=0, double y=0): x(x), y(y) {}

    Java FTW

    Marcelo Póvoa

    19 de September de 2012 at 12:16

    • Alright. I didn’t see the code but this has the same behavior, because the point object can be constructed with a single argument.

      BTW don’t blame C++, you probably often use this feature without knowing. It make things smoother to the programmers :)

      Murilo Adriano

      19 de September de 2012 at 18:12


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 582 other followers

%d bloggers like this: