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 ]