Re: Incomplete types and std::vector

Discussion in 'C++' started by Victor Bazarov, Feb 2, 2010.

  1. Stephen Howe wrote:
    > is this legal?


    Don't have a quote from the Standard ready, but somehow I recall that
    it's not legal. Look through the archives for "instantiate templates
    incomplete types C++" (or something like that, without quotes).

    > // Start Header File TEST.h
    > #include <vector>
    >
    > class CTest
    > {
    > public:
    > CTest();
    > ~CTest();
    >
    > private:
    > struct Incomplete;
    > std::vector<Incomplete> Vec_;
    >
    > private:
    > CTest(const CTest &);
    > CTest &operator = (const CTest &);
    > };
    > // End Header File TEST.h
    >
    > I wasnt sure of the position of incomplete types with standard containers.
    > VS2005 does not seem to mind but that is not a benchmark.


    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Feb 2, 2010
    #1
    1. Advertising

  2. * Stephen Howe:
    > On Tue, 02 Feb 2010 13:59:58 -0500, Victor Bazarov <> wrote:
    >
    >> Stephen Howe wrote:
    >>> is this legal?

    >> Don't have a quote from the Standard ready, but somehow I recall that
    >> it's not legal. Look through the archives for "instantiate templates
    >> incomplete types C++" (or something like that, without quotes).

    >
    > Thanks Victor. It is not legal
    >
    > I found Matt Austerns article here
    >
    > The Standard Librarian: Containers of Incomplete Types
    > http://www.drdobbs.com/cpp/184403814
    >
    > which is useful and good except I dont beleive he is right on one point.
    >
    > You can have function declarations (not definitions) where the arguments
    > and return type are incomplete types.


    Yes.

    To be precise, Matt Austern, then chair of the library working group of the C++
    standardization committee, wrote "You can't pass or return incomplete types by
    value, for the same reason that you can't define variables of an incomplete
    type.", in the context of function declarations, and that's wrong.

    Another case of a well-known expert getting this wrong is the GOTW on PIMPL,
    where Herb Sutter, chair of the standardization committee, used std::auto_ptr
    with incomplete type...

    From which we might conclude that committee chairs don't go well with
    incomplete types.

    Or, there's something there.


    Cheers,

    - Alf
     
    Alf P. Steinbach, Feb 2, 2010
    #2
    1. Advertising

  3. Alf P. Steinbach wrote:
    >
    > Another case of a well-known expert getting this wrong is the GOTW on
    > PIMPL, where Herb Sutter, chair of the standardization committee, used
    > std::auto_ptr with incomplete type...
    >
    > From which we might conclude that committee chairs don't go well with
    > incomplete types.
    >

    I think that there was discussion about pimpl idiom (several years ago),
    incomplete types and auto_ptr. As I remember catch was that destructor
    of envelope class has to be in implementation file where definition of
    type was visible, as if not, then, auto_ptr deletes incomplete type.

    Greets
     
    Branimir Maksimovic, Feb 2, 2010
    #3
  4. Victor Bazarov

    James Kanze Guest

    Re: Incomplete types and std::vector

    On Feb 2, 9:34 pm, Branimir Maksimovic <> wrote:
    > Alf P. Steinbach wrote:


    > > Another case of a well-known expert getting this wrong is
    > > the GOTW on PIMPL, where Herb Sutter, chair of the
    > > standardization committee, used std::auto_ptr with
    > > incomplete type...


    > > From which we might conclude that committee chairs don't go
    > > well with incomplete types.


    > I think that there was discussion about pimpl idiom (several
    > years ago), incomplete types and auto_ptr. As I remember catch
    > was that destructor of envelope class has to be in
    > implementation file where definition of type was visible, as
    > if not, then, auto_ptr deletes incomplete type.


    That's not the issue, at least not formally. The standard
    clearly says that it is undefined behavior to instantiate any of
    the templates defined in the standard over an undefined type.
    Typically, auto_ptr will only need to know the complete type in
    the destructor, and you will get away with it if the destructor
    of the pimpl is not inlined. But that's just a case of
    undefined behavior happening to work, and you won't get away
    with it if the implementation uses concepts. (And the next
    version of the standard will, I think, require a diagnostic. At
    least if concepts make it in.)

    --
    James Kanze
     
    James Kanze, Feb 2, 2010
    #4
  5. Re: Incomplete types and std::vector

    On Feb 2, 2:30 pm, James Kanze <> wrote:
    > On Feb 2, 9:34 pm, Branimir Maksimovic <> wrote:
    >
    > > Alf P. Steinbach wrote:
    > > > Another case of a well-known expert getting this wrong is
    > > > the GOTW on PIMPL, where Herb Sutter, chair of the
    > > > standardization committee, used std::auto_ptr with
    > > > incomplete type...
    > > > From which we might conclude that committee chairs don't go
    > > > well with incomplete types.

    > > I think that there was discussion about pimpl idiom (several
    > > years ago), incomplete types and auto_ptr. As I remember catch
    > > was that destructor of envelope class has to be in
    > > implementation file where definition of type was visible, as
    > > if not, then, auto_ptr  deletes incomplete type.

    >
    > That's not the issue, at least not formally.  The standard
    > clearly says that it is undefined behavior to instantiate any of
    > the templates defined in the standard over an undefined type.
    > Typically, auto_ptr will only need to know the complete type in
    > the destructor, and you will get away with it if the destructor
    > of the pimpl is not inlined.  But that's just a case of
    > undefined behavior happening to work, and you won't get away
    > with it if the implementation uses concepts.  (And the next
    > version of the standard will, I think, require a diagnostic.  At
    > least if concepts make it in.)


    Could you explain this to me then? Why was it ever allowed to delete a
    pointer to an incomplete type? As I understand it, the compiler must
    already know if the type is complete or incomplete. It has to know
    which destructor to call at compile time. If it can always detect it,
    and it's always an error (aka undefined behavior), why not require a
    diagnostic instead of call it undefined behavior? Dittos for deleting
    a void pointer. Why allow that? I've hit numerous bugs and wasted a
    lot of time tracking down memory leaks because of this IMO silly
    mistake in the standard, and because of lack of QoI in modern
    commercial compilers. At least gcc will issue warnings about these two
    cases with the proper flags, so the script calling gcc can check the
    log for these warnings and fail the build. Visual studios
    unfortunately will not even issue a warning in one of these cases even
    with all of the relevant flags enabled.
     
    Joshua Maurice, Feb 2, 2010
    #5
  6. Re: Incomplete types and std::vector

    James Kanze wrote:
    > That's not the issue, at least not formally. The standard
    > clearly says that it is undefined behavior to instantiate any of
    > the templates defined in the standard over an undefined type.
    > Typically, auto_ptr will only need to know the complete type in
    > the destructor, and you will get away with it if the destructor
    > of the pimpl is not inlined. But that's just a case of
    > undefined behavior happening to work, and you won't get away
    > with it if the implementation uses concepts. (And the next
    > version of the standard will, I think, require a diagnostic. At
    > least if concepts make it in.)


    I have no idea what are concepts, but does it mean that the compilation
    of the code using pimpl is going to fail with the c++0x?
     
    Vladimir Jovic, Feb 3, 2010
    #6
  7. Victor Bazarov

    James Kanze Guest

    Re: Incomplete types and std::vector

    On Feb 2, 11:25 pm, Joshua Maurice <> wrote:
    > On Feb 2, 2:30 pm, James Kanze <> wrote:
    > > On Feb 2, 9:34 pm, Branimir Maksimovic <> wrote:

    [...]
    > Could you explain this to me then? Why was it ever allowed to
    > delete a pointer to an incomplete type?


    No, I can't explain it. It seems as incongruous to me as it
    does to you. IMHO, it should be an error, requiring a
    diagnostic.

    --
    James Kanze
     
    James Kanze, Feb 3, 2010
    #7
  8. Victor Bazarov

    James Kanze Guest

    Re: Incomplete types and std::vector

    On Feb 3, 8:39 am, Vladimir Jovic <> wrote:
    > James Kanze wrote:
    > > That's not the issue, at least not formally. The standard
    > > clearly says that it is undefined behavior to instantiate
    > > any of the templates defined in the standard over an
    > > undefined type. Typically, auto_ptr will only need to know
    > > the complete type in the destructor, and you will get away
    > > with it if the destructor of the pimpl is not inlined. But
    > > that's just a case of undefined behavior happening to work,
    > > and you won't get away with it if the implementation uses
    > > concepts. (And the next version of the standard will, I
    > > think, require a diagnostic. At least if concepts make it
    > > in.)


    > I have no idea what are concepts, but does it mean that the
    > compilation of the code using pimpl is going to fail with the
    > c++0x?


    Not if you do it right. (And concepts are simply a means of
    getting improved compile time error checking from templates.
    The standard says, for example, that a type used to instantiate
    std::vector must be assignable and copiable: without concepts,
    you don't get an error until you try to instantiate one of the
    functions which actually assigns or copies; with concepts, you
    can get an error any time you try to instantiate the vector.)

    --
    James Kanze
     
    James Kanze, Feb 3, 2010
    #8
  9. Victor Bazarov

    James Kanze Guest

    Re: Incomplete types and std::vector

    On Feb 3, 5:16 pm, Juha Nieminen <> wrote:
    > James Kanze wrote:
    > > That's not the issue, at least not formally. The standard
    > > clearly says that it is undefined behavior to instantiate
    > > any of the templates defined in the standard over an
    > > undefined type. Typically, auto_ptr will only need to know
    > > the complete type in the destructor, and you will get away
    > > with it if the destructor of the pimpl is not inlined. But
    > > that's just a case of undefined behavior happening to work,
    > > and you won't get away with it if the implementation uses
    > > concepts. (And the next version of the standard will, I
    > > think, require a diagnostic. At least if concepts make it
    > > in.)


    > boost::shared_ptr doesn't require for the type to be complete.
    > Since the new standard will include a similar smart pointer,
    > will it lose that feature?


    I don't think so. IIRC, the wording in the latest draft I saw
    said that this case was undefined, unless otherwise specified.
    And the description of shared_ptr specified otherwise. (But I
    think it's about the only template which did.)

    --
    James Kanze
     
    James Kanze, Feb 3, 2010
    #9
  10. Victor Bazarov

    James Kanze Guest

    Re: Incomplete types and std::vector

    On Feb 3, 5:32 pm, "Leigh Johnston" <> wrote:
    > "Juha Nieminen" <> wrote in message


    [...]
    > I
    > asked a question elsewhere about the status of auto_ptr. It seems to be
    > quite common to use auto_ptr to implement the pimpl idiom.


    Does it? My thoughts here are: why bother. You still need an
    out of line destructor, and if you have to write a destructor
    anyway, what's the problem with putting a delete in it, and
    using a raw pointer. The whole point of the compilation
    firewall idiom is to reduce include file dependencies, and any
    smart pointer will require at least one extra include file.

    --
    James Kanze
     
    James Kanze, Feb 3, 2010
    #10
  11. Re: Incomplete types and std::vector

    * James Kanze:
    > On Feb 2, 11:25 pm, Joshua Maurice <> wrote:
    >> On Feb 2, 2:30 pm, James Kanze <> wrote:
    >>> On Feb 2, 9:34 pm, Branimir Maksimovic <> wrote:

    > [...]
    >> Could you explain this to me then? Why was it ever allowed to
    >> delete a pointer to an incomplete type?

    >
    > No, I can't explain it. It seems as incongruous to me as it
    > does to you. IMHO, it should be an error, requiring a
    > diagnostic.


    'delete p' where *p is of statically incomplete type T is Undefined Behavior if
    T has a non-trivial destructor or deallocation function, by §5.3.5/5.

    'delete p' where *p is of static type 'void' is Undefined Behavior by §5.3.5/3,
    since there are no actual objects of type 'void'.

    There's even a note explaning that particular consequence.


    Cheers & hth.,

    - Alf
     
    Alf P. Steinbach, Feb 3, 2010
    #11
  12. Re: Incomplete types and std::vector

    On Feb 3, 12:51 pm, "Alf P. Steinbach" <> wrote:
    > * James Kanze:
    >
    > > On Feb 2, 11:25 pm, Joshua Maurice <> wrote:
    > >> On Feb 2, 2:30 pm, James Kanze <> wrote:
    > >>> On Feb 2, 9:34 pm, Branimir Maksimovic <> wrote:

    > >     [...]
    > >> Could you explain this to me then? Why was it ever allowed to
    > >> delete a pointer to an incomplete type?

    >
    > > No, I can't explain it.  It seems as incongruous to me as it
    > > does to you.  IMHO, it should be an error, requiring a
    > > diagnostic.

    >
    > 'delete p' where *p is of statically incomplete type T is Undefined Behavior if
    > T has a non-trivial destructor or deallocation function, by §5.3.5/5.
    >
    > 'delete p' where *p is of static type 'void' is Undefined Behavior by §5.3.5/3,
    > since there are no actual objects of type 'void'.
    >
    > There's even a note explaning that particular consequence.


    That's the rule. I'm asking why was that ever chosen to be the rule.

    Currently, for delete *p, if *p is a complete non-void type with a
    trivial destructor and trivial deallocation function, then it's
    defined behavior. Otherwise it's undefined behavior. I argue that all
    cases of delete *p, where *p is void type or an incomplete type,
    should be "diagnostic required". I don't see any good reason for
    anything different. The current rules in the standard border on brain
    damaged.
     
    Joshua Maurice, Feb 3, 2010
    #12
  13. Victor Bazarov

    James Kanze Guest

    Re: Incomplete types and std::vector

    On Feb 3, 9:59 pm, "Leigh Johnston" <> wrote:
    > >> I asked a question elsewhere about the status of auto_ptr.
    > >> It seems to be quite common to use auto_ptr to implement
    > >> the pimpl idiom.


    > > Does it? My thoughts here are: why bother. You still need
    > > an out of line destructor, and if you have to write a
    > > destructor anyway, what's the problem with putting a delete
    > > in it, and using a raw pointer. The whole point of the
    > > compilation firewall idiom is to reduce include file
    > > dependencies, and any smart pointer will require at least
    > > one extra include file.


    > You need both an out of line constructor and destructor.


    Yes, but an inline constructor for the compilation firewall
    idiom doesn't make any sense. It's only the destructor which
    raises a question.

    > Using auto_ptr for pimpl does in fact reduce file dependencies
    > which is exactly why I do it.


    Using the compilation firewall idiom seriously reduces file
    dependencies. Using std::auto_ptr to implement adds one
    dependency, on <memory>. And doesn't buy you anything anywhere
    else. So why bother. This is a case where a raw pointer is the
    simplest and most effective answer.

    > The translation unit containing the ctor and dtor of the class
    > containing the pimpl will have access to the complete type.


    Obviously. That's what's required.

    > Read Herb
    > Sutter'shttp://www.gotw.ca/publications/using_auto_ptr_effectively.htmit
    > advocates using auto_ptr for pimpl.


    I've doubtlessly read it, but I'm not convinced. I repeat: what
    does std::auto_ptr buy you, compared to a raw pointer?

    > I use auto_ptr for pimpl but I will change it to use
    > unique_ptr when I get a C++0x compiler. Yes I am aware that
    > it is "officially" undefined behaviour to use auto_ptr for
    > pimpl. The only reason it remains so in C++0x is that
    > auto_ptr has been deprecated as far as I can tell.


    I use raw pointers for the compilation firewall idiom. Works
    just as well as auto_ptr, and is a lot simpler.

    --
    James Kanze
     
    James Kanze, Feb 4, 2010
    #13
  14. Re: Incomplete types and std::vector

    On Feb 5, 1:21 pm, "Leigh Johnston" <> wrote:
    > "Juha Nieminen" <> wrote in message
    >
    > news:hki1dc$1jhf$...
    >
    > > Leigh Johnston wrote:

    >
    > >>> I've doubtlessly read it, but I'm not convinced.  I repeat: what
    > >>> does std::auto_ptr buy you, compared to a raw pointer?

    >
    > >> std::auto_ptr buys you ownership semantics with RAII (no memory leak if
    > >> exception is thrown during construction of class owning the pimpl
    > >> object). The alternative is to write your own version of something
    > >> similar to std::auto_ptr but why bother?

    >
    > >  I think that the point is that using std::auto_ptr in the pimpl idiom
    > > doesn't save much work. You still need to write an explicit destructor
    > > (and possibly constructor) and forbid copying and assignment of the
    > > class. Basically you are more or less simply changing a "delete data;"
    > > in the destructor to a "std::auto_ptr" in the class declaration. Not
    > > much of a saving.

    >
    > It is still a saving and saves you from using local (automatic) auto_ptrs in
    > the constructor body especially if the class has more than one pimpl object
    > (think about exception safety - a bad_alloc exception could be thrown if you
    > create more than one pimpl object or anything else that could throw an
    > exception in the constructor body).  "delete data;" in the destructor would
    > never be called if the constructor body throws an exception.
    >
    > RAII is one of the features that makes C++ great, not using it is plain
    > silly.


    My 2 cents: Generally when I use pimpl, it's

    //header
    #include <string>

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

    std::string getName() const; //ex func
    //etc.
    private:
    class FooImpl;
    FooImpl * impl;
    };

    //cpp
    class Foo::FooImpl
    {
    public:
    //impl
    };

    Foo::Foo() : impl(new Foo::FooImpl) {}
    Foo::~Foo() { delete impl; }
    std::string Foo::getName() const { /*return impl->getName();*/ return
    ""; }

    //end example

    Most uses of pimpl are as simple as this. I would be skeptical of a
    design which had "multiple pimpl pointers". The constructor body of
    Foo is generally that, no more, no less, give or take the names.
    However, I suppose there's nothing to lose by using std::auto_ptr
    either.

    Finally, I feel stupid. Could someone explain to me how this works,
    how std::auto_ptr::~auto_ptr "finds" the name Foo as a complete type?
    Probably something to do with template lookup rules, the two phase
    lookup, lookup based on instantiation context and declaring context,
    and the rest of that nastiness. Playing around with it, I proved to
    myself that it does work if Foo::~Foo is defined in a scope where
    FooImpl is a complete type, and that it deletes it as an incomplete
    type if Foo::~Foo is declared in a different translation unit.

    I would think that it would be undefined behavior if Foo::~Foo is
    defined in a scope where FooImpl is an incomplete type. Interestingly
    enough, if I move the Foo::~Foo definition to before the FooImpl class
    definition in the same translation unit, a scope where FooImpl is an
    incomplete type, visual studios 2008 still deletes it as a complete
    type, which completely mystifies me. Is this visual studios protecting
    me from myself, and making it "do the right thing" in a case of
    undefined behavior? Or do I completely fail at understanding the
    template instantiation and name lookup rules?

    I suppose the danger with std::auto_ptr is no greater than the danger
    with a naked pointer: you get a delete of an incomplete type pointer
    either way, and a good compiler will warn you either way. However,
    this just bugs me as questionable style as at the point of declaration
    of "std::auto_ptr<Foo::FooImpl> Foo::impl", the type FooImpl is an
    incomplete type. That just seems like a bad idea, or something.
    Perhaps if I better understood the template magic I would not think
    so.
     
    Joshua Maurice, Feb 6, 2010
    #14
  15. Victor Bazarov

    James Kanze Guest

    Re: Incomplete types and std::vector

    On Feb 4, 11:07 pm, "Leigh Johnston" <> wrote:
    > > I've doubtlessly read it, but I'm not convinced. I repeat:
    > > what does std::auto_ptr buy you, compared to a raw pointer?


    > std::auto_ptr buys you ownership semantics with RAII (no
    > memory leak if exception is thrown during construction of
    > class owning the pimpl object). The alternative is to write
    > your own version of something similar to std::auto_ptr but why
    > bother? I will use unique_ptr instead when it is available.


    Sorry, but that's just false. Whether you use auto_ptr or a raw
    pointer changes absolutely nothing during construction.

    > It is silly saying a <memory> dependency is undesirable.


    It's not really a big point, but why add the dependency if it
    doesn't buy you anything.

    --
    James Kanze
     
    James Kanze, Feb 7, 2010
    #15
  16. Victor Bazarov

    James Kanze Guest

    Re: Incomplete types and std::vector

    On Feb 5, 9:21 pm, "Leigh Johnston" <> wrote:
    > "Juha Nieminen" <> wrote in message


    > news:hki1dc$1jhf$...
    > > Leigh Johnston wrote:


    > >>> I've doubtlessly read it, but I'm not convinced. I
    > >>> repeat: what does std::auto_ptr buy you, compared to a raw
    > >>> pointer?


    > >> std::auto_ptr buys you ownership semantics with RAII (no
    > >> memory leak if exception is thrown during construction of
    > >> class owning the pimpl object). The alternative is to write
    > >> your own version of something similar to std::auto_ptr but
    > >> why bother?


    > > I think that the point is that using std::auto_ptr in the
    > > pimpl idiom doesn't save much work. You still need to write
    > > an explicit destructor (and possibly constructor) and forbid
    > > copying and assignment of the class. Basically you are more
    > > or less simply changing a "delete data;" in the destructor
    > > to a "std::auto_ptr" in the class declaration. Not much of a
    > > saving.


    > It is still a saving and saves you from using local
    > (automatic) auto_ptrs in the constructor body especially if
    > the class has more than one pimpl object (think about
    > exception safety - a bad_alloc exception could be thrown if
    > you create more than one pimpl object or anything else that
    > could throw an exception in the constructor body).


    If your main object contains more than one pointer, it's not the
    compilation firewall idiom---you're doing something else, and
    other rules apply. And as long as there's only one pointer,
    auto_ptr buys you absolutely nothing.

    > "delete data;" in the destructor would never be called if the
    > constructor body throws an exception.


    There is no "constructor body" in the compilation firewall
    idiom. The constructor, by definition, is simply:

    MyType::MyType(...) : myImpl( new Impl(...) ) {}

    Anything else, and you're not talking about the compilation
    firewall idiom, but something else.

    > RAII is one of the features that makes C++ great, not using it
    > is plain silly.


    Like everything else, you use it when appropriate. When it buys
    you something.

    (And using smart pointers in a class object really isn't the
    normal use of RAII, which depends on deterministic destructor
    call.)

    --
    James Kanze
     
    James Kanze, Feb 7, 2010
    #16
  17. Victor Bazarov

    James Kanze Guest

    Re: Incomplete types and std::vector

    On Feb 6, 6:07 am, Joshua Maurice <> wrote:
    > On Feb 5, 1:21 pm, "Leigh Johnston" <> wrote:
    > > "Juha Nieminen" <> wrote in message

    > My 2 cents: Generally when I use pimpl, it's


    > //header
    > #include <string>


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


    > std::string getName() const; //ex func
    > //etc.
    > private:
    > class FooImpl;
    > FooImpl * impl;
    > };


    > //cpp
    > class Foo::FooImpl
    > {
    > public:
    > //impl
    > };


    > Foo::Foo() : impl(new Foo::FooImpl) {}
    > Foo::~Foo() { delete impl; }
    > std::string Foo::getName() const { /*return impl->getName();*/ return
    > "";
    > }
    > //end example


    > Most uses of pimpl are as simple as this.


    That's how Herb Sutter defined it, and since he invented the
    term, I think it just adds to the confusion if you decide to use
    some other definition. (It's not a term like OO, which already
    has hundreds of subtly different definitions.)

    > I would be skeptical of a design which had "multiple pimpl
    > pointers". The constructor body of Foo is generally that, no
    > more, no less, give or take the names. However, I suppose
    > there's nothing to lose by using std::auto_ptr either.


    Except for an additional include in the header, no. And perhaps
    a false sense of security; typically, when you use auto_ptr in
    an object, you don't need to provide a user defined destructor.

    > Finally, I feel stupid. Could someone explain to me how this
    > works, how std::auto_ptr::~auto_ptr "finds" the name Foo as a
    > complete type? Probably something to do with template lookup
    > rules, the two phase lookup, lookup based on instantiation
    > context and declaring context, and the rest of that nastiness.
    > Playing around with it, I proved to myself that it does work
    > if Foo::~Foo is defined in a scope where FooImpl is a complete
    > type, and that it deletes it as an incomplete type if
    > Foo::~Foo is declared in a different translation unit.


    > I would think that it would be undefined behavior if Foo::~Foo
    > is defined in a scope where FooImpl is an incomplete type.


    In fact, it's undefined behavior if the class is even
    instantiated in a context where Foo is not complete. I wouldn't
    be surprised if some implementations complained.

    > Interestingly enough, if I move the Foo::~Foo definition to
    > before the FooImpl class definition in the same translation
    > unit, a scope where FooImpl is an incomplete type, visual
    > studios 2008 still deletes it as a complete type, which
    > completely mystifies me. Is this visual studios protecting me
    > from myself, and making it "do the right thing" in a case of
    > undefined behavior? Or do I completely fail at understanding
    > the template instantiation and name lookup rules?


    It's undefined behavior; in practice, it will depend on how the
    compiler instantiates templates.

    --
    James Kanze
     
    James Kanze, Feb 7, 2010
    #17
  18. Victor Bazarov

    James Kanze Guest

    Re: Incomplete types and std::vector

    On Feb 6, 1:23 pm, "Leigh Johnston" <> wrote:

    [...]
    > > Most uses of pimpl are as simple as this. I would be
    > > skeptical of a design which had "multiple pimpl pointers".
    > > The constructor body of Foo is generally that, no more, no
    > > less, give or take the names. However, I suppose there's
    > > nothing to lose by using std::auto_ptr either.


    > Not really, there is nothing wrong with a top-level "model"
    > class containing multiple objects that you don't want to
    > expose in the model header file to reduce dependencies and
    > compilation times.


    There's nothing wrong with a top-level model class doing a lot
    of things; most of the ones I deal with today contain things
    like std::vector<double>, for example. But we were talking here
    about the pimpl idiom. As defined by Herb Sutter. (Formally,
    it's really the compilation firewall idiom, and before Herb
    popularized it, it was often known as the Cheshire cat
    idiom---named by Jim Adcock?) It's a very specific idiom.

    > > I would think that it would be undefined behavior if
    > > Foo::~Foo is defined in a scope where FooImpl is an
    > > incomplete type. Interestingly enough, if I move the
    > > Foo::~Foo definition to before the FooImpl class definition
    > > in the same translation unit, a scope where FooImpl is an
    > > incomplete type, visual studios 2008 still deletes it as a
    > > complete type, which completely mystifies me. Is this visual
    > > studios protecting me from myself, and making it "do the
    > > right thing" in a case of undefined behavior? Or do I
    > > completely fail at understanding the template instantiation
    > > and name lookup rules?


    > Comeau complains if you do this so I wouldn't trust an
    > individual compiler's behaviour as to what constitutes
    > undefined behaviour or not.


    The standard says that instantiating std::auto_ptr (or any
    template defined in the standard) over an incomplete type is
    undefined behavior). In this case, the standard probably could
    have been a bit laxer, and only required a complete type where
    the destructor was instantiated. But the standard having
    specified this restriction, it wouldn't surprise me if some
    compiler/library implementation enforced it. (G++ enforces a
    lot of this sort of thing in its library implementation; I don't
    know off hand if this particular case is covered or not,
    however.)

    --
    James Kanze
     
    James Kanze, Feb 7, 2010
    #18
  19. Re: Incomplete types and std::vector

    * James Kanze:
    > On Feb 4, 11:07 pm, "Leigh Johnston" <> wrote:
    >>> I've doubtlessly read it, but I'm not convinced. I repeat:
    >>> what does std::auto_ptr buy you, compared to a raw pointer?

    >
    >> std::auto_ptr buys you ownership semantics with RAII (no
    >> memory leak if exception is thrown during construction of
    >> class owning the pimpl object). The alternative is to write
    >> your own version of something similar to std::auto_ptr but why
    >> bother? I will use unique_ptr instead when it is available.

    >
    > Sorry, but that's just false. Whether you use auto_ptr or a raw
    > pointer changes absolutely nothing during construction.


    I think Leigh is referring to something like

    Foo::Foo()
    : myImpl( std::auto_ptr<Impl>( new Impl ) )
    {
    // Statement X that might trow
    }

    If X throws then statements in ~Foo are not executed.

    However, the smart pointer ensures that the Impl instance is deleted.

    This avoids doing silly things like

    Foo::Foo()
    {
    std::auto_ptr<Impl> pImpl( new Impl );

    myImpl = pImpl.get();
    // Statement X that might throw
    pImpl.release();
    }

    or even worse with try-catch.

    A main catch is that one is using knowledge of how a std::auto_ptr is usually
    implemented in order to create code that will work in practice in spite of
    formally Undefined Behavior, which is a bit fragile...

    And really, what's used is not std::auto_ptr's ownership transfer semantics, but
    just its RAII cleanup.

    And so even the simplest of the simplest RAII cleanup class would do as a
    well-defined substitute, e.g.

    template< typename T >
    struct AutoDestroyed
    {
    T* p;

    ~AutoDestroyed() { destroy( p ); } // Define 'destroy' per type T.
    AutoDestroyed( T* const p_ ): p(p_) {}

    AutoDestroyed( AutoDestroyed const& );
    AutoDestroyed& operator=( AutoDestroyed const& );
    };


    >> It is silly saying a <memory> dependency is undesirable.

    >
    > It's not really a big point, but why add the dependency if it
    > doesn't buy you anything.


    See above.


    Cheers,

    - Alf
     
    Alf P. Steinbach, Feb 7, 2010
    #19
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Anonymous
    Replies:
    20
    Views:
    4,388
    Pete Becker
    Mar 30, 2005
  2. aegis

    sizeof and incomplete types

    aegis, Dec 4, 2005, in forum: C Programming
    Replies:
    2
    Views:
    352
    Eric Sosman
    Dec 4, 2005
  3. Jason Heyes
    Replies:
    8
    Views:
    755
    Andrew Koenig
    Jan 15, 2006
  4. Replies:
    8
    Views:
    1,987
    Csaba
    Feb 18, 2006
  5. Rune Allnor
    Replies:
    4
    Views:
    983
    Rune Allnor
    Dec 11, 2008
Loading...

Share This Page