Topic: Manually invoking constructors


Author: smeyers@teleport.com (Scott Meyers)
Date: 1997/02/11
Raw View
In a letter in the March 1997 Dr. Dobbs Journal, Poul Costinsky claims
to have a way to manually call constructors and destructors that is
"100 percent portable, legal, and exhibits good style."  This is his
code, with main added so it can be fed to a compiler:

  class Foo {
  public:
    Foo();
    ~Foo();
  };

  int main()
  {
    Foo *pBar = (Foo*) malloc(10*sizeof(Foo));
    for (int i = 0; i < 10; i++) (pBar+i)->Foo::Foo();   // !
    pBar = (Foo*)realloc(pBar, 11*sizeof(Foo));
    (pBar+10)->Foo::Foo();                               // !
    for (int i = 0; i < 11; i++) (pBar+i)->Foo::~Foo();
    free(pBar);

    return 0;
  }

I believe the two lines marked should elicit an error, because it's not
legal to invoke a constructor as a regular member function, right?  Yet
I can't find wording to this effect in the December DWP, at least not
in section 12.1 ("Constructors").  Is it possible that this code is
actually legal?  I know that Poul can do what he wants to do via
placement new, but what about the syntax he uses?  I've always believed
it was prohibited, but I can't find the prohibition.

For what it's worth, both VC4.2 and g++ 2.7.2 accept the code above.

Scott

--
Scott Meyers, Ph.D.                  Voice: 503/638-6028
C++ Consulting and Training          Fax:   503/638-6614
Author of "Effective C++"            Email: smeyers@netcom.com
  and "More Effective C++"           WWW:   http://www.teleport.com/~smeyers


[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Michael R Cook <mcook@cognex.com>
Date: 1997/02/11
Raw View
 SM> I've always believed it was prohibited, but I can't find the prohibition.

I believe you're right, and I think that the argument is based on this
sentence (the first sentence in 12.1 Constructors):

 Constructors do not have names.

So, since constructors don't have names, you can't invoke them explicitly.
The language would need a special rule to allow the explicit invocation of
constructors, but the language has no such rule.

In other words, you can't do it--not because the dwp says you can't, but
because the dwp doesn't say you can.
--
 Michael Cook <mcook@cognex.com>        <http://ftp.cognex.com/~mcook/>
 Telephone: +1 508 650 3251                        Fax: +1 508 650 3336
 Cognex Corporation, One Vision Drive, Natick, Massachusetts 01760-2059
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Pete Becker <pbecker@oec.com>
Date: 1997/02/11
Raw View
Scott Meyers wrote:
>
> In a letter in the March 1997 Dr. Dobbs Journal, Poul Costinsky claims
> to have a way to manually call constructors and destructors that is
> "100 percent portable, legal, and exhibits good style."  This is his
> code, with main added so it can be fed to a compiler:
>
>   class Foo {
>   public:
>     Foo();
>     ~Foo();
>   };
>
>   int main()
>   {
>     Foo *pBar = (Foo*) malloc(10*sizeof(Foo));
>     for (int i = 0; i < 10; i++) (pBar+i)->Foo::Foo();   // !
>     pBar = (Foo*)realloc(pBar, 11*sizeof(Foo));
>     (pBar+10)->Foo::Foo();                               // !
>     for (int i = 0; i < 11; i++) (pBar+i)->Foo::~Foo();
>     free(pBar);
>
>     return 0;
>   }
>
> I believe the two lines marked should elicit an error, because it's not
> legal to invoke a constructor as a regular member function, right?  Yet
> I can't find wording to this effect in the December DWP, at least not
> in section 12.1 ("Constructors").  Is it possible that this code is
> actually legal?  I know that Poul can do what he wants to do via
> placement new, but what about the syntax he uses?  I've always believed
> it was prohibited, but I can't find the prohibition.
>
Here's the pertinent language from clause 12.1:

 A constructor is used to initialize objects of its class type.
 Because constructors do not have names, they are never found
 during name lookup; however an explicit type conversion using
 the functional notation (5.2.3) will cause a constructor to be
 called to initialize an object.

That is, foo::foo() does not invoke a constructor, because a constructor
has no name. Rather, it performs a type conversion, i.e. it constructs
an unnamed object using the default constructor. It's meaningless to
invoke this type conversion with the -> operator. There's also language
in clause 3.8 that says that there's very little you can do meaningfully
with a pointer to an object after memory has been allocated for the
object but before the objects constructor has run. Basically you can
treat the pointer as a void *.

> For what it's worth, both VC4.2 and g++ 2.7.2 accept the code above.

For what it's worth, BC++ 5.0 rejects this code with a somewhat obscure
error message that "'foo' is not a member of 'foo'". That's technically
correct, since the name foo is not found during lookup.
 -- Pete
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Alexandre Oliva <oliva@dcc.unicamp.br>
Date: 1997/02/12
Raw View
Scott Meyers writes:

> In a letter in the March 1997 Dr. Dobbs Journal, Poul Costinsky claims
> to have a way to manually call constructors and destructors that is
> "100 percent portable, legal, and exhibits good style."  This is his
> code, with main added so it can be fed to a compiler:

>     Foo *pBar = (Foo*) malloc(10*sizeof(Foo));
>     for (int i = 0; i < 10; i++) (pBar+i)->Foo::Foo();   // !
>     pBar = (Foo*)realloc(pBar, 11*sizeof(Foo));
>     (pBar+10)->Foo::Foo();                               // !
>     for (int i = 0; i < 11; i++) (pBar+i)->Foo::~Foo();
>     free(pBar);

> I believe the two lines marked should elicit an error, because it's not
> legal to invoke a constructor as a regular member function, right?

Right, constructors do not have names, so they are never found in name
lookup [class.ctor par2], so this construction is illegal.  Placement
new should be used instead.  Explicit destructor invocation is
allowed, however [class.dtor par12-15], as there's no delete
expression that invokes the placement delete.

> For what it's worth, both VC4.2 and g++ 2.7.2 accept the code above.

They shouldn't, actually.  The next release of g++ will not accept
explicit constructor invocations, by the way.

--
Alexandre Oliva
mailto:oliva@dcc.unicamp.br mailto:aoliva@acm.org
Universidade Estadual de Campinas, SP, Brasil
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Stephen.Clamage@eng.sun.com (Steve Clamage)
Date: 1997/02/07
Raw View
In article 1@linda.teleport.com, smeyers@teleport.com (Scott Meyers) writes:
>In a letter in the March 1997 Dr. Dobbs Journal, Poul Costinsky claims
>to have a way to manually call constructors and destructors that is
>"100 percent portable, legal, and exhibits good style."  This is his
>code, with main added so it can be fed to a compiler:
>
>  class Foo {
>  public:
>    Foo();
>    ~Foo();
>  };
>
>  int main()
>  {
>    Foo *pBar = (Foo*) malloc(10*sizeof(Foo));
>    for (int i = 0; i < 10; i++) (pBar+i)->Foo::Foo();   // !
>    pBar = (Foo*)realloc(pBar, 11*sizeof(Foo));
>    (pBar+10)->Foo::Foo();                               // !
>    for (int i = 0; i < 11; i++) (pBar+i)->Foo::~Foo();
>    free(pBar);
>
>    return 0;
>  }
>
>I believe the two lines marked should elicit an error, because it's not
>legal to invoke a constructor as a regular member function, right?  Yet
>I can't find wording to this effect in the December DWP, at least not
>in section 12.1 ("Constructors").

Here are the first two paragraphs from 12.1:
-------------------------------------------------------
Constructors do not have names. A special declarator syntax using an
optional function-specifier (7.1.2) followed by the constructor's
class name followed by a parameter list is used to declare or define the
constructor. In such a declaration, optional parentheses around the
constructor class name are ignored.
[Example deleted]

A constructor is used to initialize objects of its class type. Because
constructors do not have names, they are never found during name lookup;
however an explicit type conversion using the functional notation (5.2.3)
will cause a constructor to be called to initialize an object.
-------------------------------------------------------

Since a constructor does not have a name, and thus cannot be found
during name lookup, what does this code from the example mean?
 (pBar+i)->Foo::Foo();
The locution Foo::Foo in this case cannot refer to a constructor, so
whatever it does, it doesn't invoke a constructor. But a class Foo cannot
have any member whose name is Foo, so the code cannot be valid, and must
result in a diagnostic.

I'm told that some compilers allow constructor "calls" as in the
example. If so, that would be a non-standard extension. (It would be
a pure extension, since it gives a defined meaning to otherwise
invalid code.)

As many people have noted, you can use "placement new" to get the
desired effect with valid and portable code.
---
Steve Clamage, stephen.clamage@eng.sun.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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]