Topic: Indicating constructor-time calls (proposed language improvement)


Author: John Nagle <nagle@animats.com>
Date: Wed, 15 May 2002 18:44:13 GMT
Raw View
    One of the classic C++ issues is the calling of
a function with an argument that isn't fully constructed.
Constructors are currently allowed to call methods of the
class, even though the object isn't fully constructed.
For example,

 class Foo {
 private:
  int m_n;
 public:
  reset()  // reset to initial state
  { m_n = 0; }
 public:
  Foo()   // constructor
  { reset(); } // just reset
 };

This is allowed, even though "reset" is called on an object that
isn't yet constructed.

    On the other hand, this isn't allowed, but it's common to use
a pragma to allow it:

 class Bar;

 // Class Foo - contains a reference to a related Bar
      class Foo {
 private:
  Bar& m_bar;
 public:
  Foo(Bar& relatedbar)
   : m_bar(relatedbar) {}
 };

 // Class Bar - contains a Foo related to it.
 class Bar {
 private:
  Foo m_myfoo;
 public:
  Bar() // constructor
  : m_myfoo(*this) {} // WARNING - unconstructed object
 };

Suppose we have a attribute "construction", akin to "volatile",
"mutable", "const", etc.  A data item with the "construction" attribute
is known to be under construction, and its uses are limited. The above
would look like

 class Foo {
 private:
  int m_n;
 public:
  reset() construction; // Callable from a constructor
  { m_n = 0; }
 public:
  Foo()   // constructor
  { reset(); } // just reset
 };

And the second example:

 class Bar;

 // Class Foo - contains a reference to a related Bar
      class Foo {
 private:
  Bar& m_bar;
 public:
  Foo(construction Bar& relatedbar)
   : m_bar(relatedbar) {}
 };

 // Class Bar - contains a Foo related to it.
 class Bar {
 private:
  Foo m_myfoo;
 public:
  Bar() // constructor
  : m_myfoo(*this) {} // OK
 };

Now it's clear what's going on.  class "Bar" gets an unconstructed
object, and can only do things appropriate to an unconstructed
object, like save a reference to it.

***UNSAFE*** Bar could call another function that didn't know
the object was under construction.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Garry Lancaster" <glancaster@ntlworld.com>
Date: Wed, 15 May 2002 21:24:48 GMT
Raw View
John Nagle:
> This is allowed, even though "reset" is called on an object that
> isn't yet constructed.
>
>     On the other hand, this isn't allowed, but it's common to use
> a pragma to allow it:
>
> class Bar;
>
> // Class Foo - contains a reference to a related Bar
>      class Foo {
> private:
> Bar& m_bar;
> public:
> Foo(Bar& relatedbar)
> : m_bar(relatedbar) {}
> };
>
> // Class Bar - contains a Foo related to it.
> class Bar {
> private:
> Foo m_myfoo;
> public:
> Bar() // constructor
> : m_myfoo(*this) {} // WARNING - unconstructed object
> };

What makes you think it's not allowed? Hint:
a compiler warning isn't sufficient.

Which compiler are you using? (I guess it's
MSVC 6. I could be wrong.)

Kind regards

Garry Lancaster
Codemill Ltd
Visit our web site at http://www.codemill.net

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Allan_W@my-dejanews.com (Allan W)
Date: Thu, 16 May 2002 20:04:58 GMT
Raw View
John Nagle <nagle@animats.com> wrote
> this isn't allowed, but it's common to use
> a pragma to allow it:
>
>  class Bar;
>
>  // Class Foo - contains a reference to a related Bar
>       class Foo {
>  private:
>   Bar& m_bar;
>  public:
>   Foo(Bar& relatedbar)
>    : m_bar(relatedbar) {}
>  };
>
>  // Class Bar - contains a Foo related to it.
>  class Bar {
>  private:
>   Foo m_myfoo;
>  public:
>   Bar() // constructor
>   : m_myfoo(*this) {} // WARNING - unconstructed object
>  };

This example shows a case that is de-facto safe, even if the
compiler can't know it. A more troubling case is this:

    class Trailer; // Forward

    class Car {
        Trailer &trailer;
    public:
        Car(Trailer&);
    };

    class Trailer {
        Car car;
        int towed;
    public:
        Trailer() :
           Car(*this), // Warning!
           towed(2)        // Had to tow the Car home!
           { }
        int tow() { return ++towed; }
    }

    Car::Car(Trailer&t) : trailer(t) { trailer.pick(); }

Trailer::tow() is called before the trailer is fully constructed.

> Suppose we have a attribute "construction", akin to "volatile",
> "mutable", "const", etc.  A data item with the "construction" attribute
> is known to be under construction, and its uses are limited.

I don't quite get it. You say the "construction" attribute indicates
that the data item "is known to be under construction." But all data
items are constructed at one point or another. Would you suggest that
when the object is being constructed, it finds the source code and
adds this attribute -- and when the object is finished being
constructed, it puts it back?

Obviously that's not what you mean, but I don't get what you DO mean.
The constructed attribute seems to mean, "supress warnings about using
this data element before it's constructed" -- but the point of those
warnings hasn't been eliminated. Code like the above won't work right,
and adding a new data attribute won't fix it.

> The above
> would look like
>
>  class Foo {
>  private:
>   int m_n;
>  public:
>   reset() construction; // Callable from a constructor
>   { m_n = 0; }
>  public:
>   Foo()   // constructor
>   { reset(); } // just reset
>  };

Meaning (I think) "callable from a constructor without warning."
But warnings are QOI issues anyway -- nothing in the standard says
that a program has to issue a warning on a legal program.

> And the second example:
>
>  class Bar;
>
>  // Class Foo - contains a reference to a related Bar
>       class Foo {
>  private:
>   Bar& m_bar;
>  public:
>   Foo(construction Bar& relatedbar)
>    : m_bar(relatedbar) {}
>  };
>
>  // Class Bar - contains a Foo related to it.
>  class Bar {
>  private:
>   Foo m_myfoo;
>  public:
>   Bar() // constructor
>   : m_myfoo(*this) {} // OK
>  };
>
> Now it's clear what's going on.  class "Bar" gets an unconstructed
> object, and can only do things appropriate to an unconstructed
> object, like save a reference to it.
>
> ***UNSAFE*** Bar could call another function that didn't know
> the object was under construction.

I think you need to explain it a bit more. Is the only difference
in the warning messages? If not, I'd like you to explain what the
program does differently in the presence of the "construction" tag.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Roger Orr" <rogero@howzatt.demon.co.uk>
Date: Fri, 17 May 2002 18:51:13 GMT
Raw View
John Nagle wrote in message <3CE2B042.7000503@animats.com>...
>    One of the classic C++ issues is the calling of
>a function with an argument that isn't fully constructed.

Destructors have a similar problem in reverse (and in my experience
this case causes more problems than the constructor case).

It would be good if any solution covered both cases.

However, it might be better as a QOI issue rather than a modification to the
core language.

Roger Orr
--
MVP in C++ at www.brainbench.com


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]