Topic: Flaw with string copy constructor wrt allocator


Author: phalpern@truffle.ma.ultranet.com (Pablo Halpern)
Date: 1998/01/22
Raw View
Matt Austern <austern@sgi.com> wrote:

>Something like the following probably comes closer to the committee's
>actual intentions.
>
>  basic_string(const basic_string& s);
>        // Use s's allocator.
>  basic_string(const basic_string& s, size_type pos, size_type n = npos,
>               const allocator_type& a = allocator_type());
>        // Use a user-provided allocator.

As per my original post, I would prefer the following:

// Copy the allocator
basic_string(const basic_string& s, size_type pos = 0,
             size_type n = npos);

// Use user-supplied allocator
basic_string(const basic_string& s, size_type pos, size_type n,
             const allocator_type& a);

The above definitions make the *default* behavior to copy the allocator,
even if only a substring is being copied.  In addition to this being
desirable in its own right, IMHO, it could be extra-efficient if strings
can share parts of their internal representations. Ultimately, however,
I don't care too much which way this defect is resolved. Just so it is
resolved.

-------------------------------------------------------------
Pablo Halpern                   phalpern@truffle.ultranet.com

I am self-employed. Therefore, my opinions *do* represent
those of my employer.
---
[ 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: Matt Austern <austern@sgi.com>
Date: 1998/01/19
Raw View
ark@research.att.com (Andrew Koenig) writes:

> > I have checked in the London draft, and it's really strange: the
> > description has changed, and is more vague, but still wrong;
> > it says that in general, arguments of type Allocator are copied
> > which means that str.get_allocator () is ignored.
>
> The history behind that decision is that the committee could not
> agree completely on how allocators should behave, but wanted to
> leave room for implementations that wanted to implement them as
> extensions.
>
> So a number of functions take allocator arguments, even though
> their description is deliberately vague about what those arguments
> do, so that specific implementations can make those descriptions
> less vague without breaking ordinary code that makes no assumptions
> about how allocators work.

That's true, but it's not quite the whole story.

Andy is right, of course, that the current status of allocators in the
standard is deliberately vague, and that that was part of a
compromise.  (He's one of the people who managed to get that
compromise accepted.)

But this is a slightly different issue.  When the committee accepted
that compromise, it also tried to define the member functions so that
they made sense whether or not implementors chose to support
allocators with non-equal instances.  Valentin is pointing out---
correctly, in my opinion---that we didn't achieve this with
basic_string<>'s copy constructor.

The problem is that basic_string<>'s copy constructor has a dual role
because of its default arguments.  It's an ordinary copy constructor,
but it's also a constructor that builds a basic_string<> from a
sequence of characters that just happens to be contained in a
basic_string<>.  Unfortunately, this extra flexibility means that
basic_string<>'s copy constructor doesn't use allocators in the same
way that other containers' copy constructors do.

I agree with Valentin and Nathan that this is a minor flaw in the
standard, and I expect it to be corrected in a future revision.
Something like the following probably comes closer to the committee's
actual intentions.

  basic_string(const basic_string& s);
        // Use s's allocator.
  basic_string(const basic_string& s, size_type pos, size_type n = npos,
               const allocator_type& a = allocator_type());
        // Use a user-provided allocator.
---
[ 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: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1998/01/12
Raw View
Pablo Halpern <phalpern@truffle.ma.ultranet.com> writes:

> Looking at my copy of CD2, I see the following constructor for
> basic_string declared as follows:
>
> basic_string(const basic_string& str, size_type pos = 0,
>              size_type n = npos, const Allocator& a = Allocator());

The table says that get_allocator () returns str.get_allocator (),
which means that 'a' is ignored.

I have checked in the London draft, and it's really strange: the
description has changed, and is more vague, but still wrong;
it says that in general, arguments of type Allocator are copied
which means that str.get_allocator () is ignored.

The Morristown draft says the same thing.

> I assume that if an implementation replaced the above with:
>
> basic_string(const basic_string& str, size_type pos = 0,
>              size_type n = npos);
> basic_string(const basic_string& str, size_type pos,
>              size_type n, const Allocator& a);
>
> such that the first form copied the allocator from its str argument,
> then such an implementation would not be standard-conforming.

You are correct. The std needs to be fixed this way, or by
changing the default argument:

basic_string(const basic_string& str, size_type pos = 0,
             size_type n = npos,
             const Allocator& a = str.get_allocator ());

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/


[ 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: phalpern@truffle.ma.ultranet.com (Pablo Halpern)
Date: 1998/01/09
Raw View
Looking at my copy of CD2, I see the following constructor for
basic_string declared as follows:

basic_string(const basic_string& str, size_type pos = 0,
             size_type n = npos, const Allocator& a = Allocator());

Since all but the first argument are defaulted, this constitutes a copy
constructor.  Given an allocator class where all instances are not
equivalent, if you use this constructor as a copy constructor, the copy
does not use the same allocator as the original. Is this what was
intended?

I assume that if an implementation replaced the above with:

basic_string(const basic_string& str, size_type pos = 0,
             size_type n = npos);
basic_string(const basic_string& str, size_type pos,
             size_type n, const Allocator& a);

such that the first form copied the allocator from its str argument,
then such an implementation would not be standard-conforming.

Is this a bad thing or am I missing something here?

-------------------------------------------------------------
Pablo Halpern                   phalpern@truffle.ultranet.com

I am self-employed. Therefore, my opinions *do* represent
those of my employer.
---
[ 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: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1998/01/09
Raw View
Pablo Halpern <phalpern@truffle.ma.ultranet.com> wrote:
>Looking at my copy of CD2, I see the following constructor for
>basic_string declared as follows:
>
>basic_string(const basic_string& str, size_type pos = 0,
>             size_type n = npos, const Allocator& a = Allocator());
>
>Since all but the first argument are defaulted, this constitutes a copy
>constructor.  Given an allocator class where all instances are not
>equivalent, if you use this constructor as a copy constructor, the copy
>does not use the same allocator as the original. Is this what was
>intended?

The behavior in the case where allocator instances are not
equivalent is implementation-defined.  So the question is
whether a correct definition can be written that is also
consistent with the Standard.

Implementations are allowed to replace default arguments with
overloaded functions, but the result must have the same semantics
as specified.

>I assume that if an implementation replaced the above with:
> [overloads]
>such that the first form copied the allocator from its str argument,
>then such an implementation would not be standard-conforming.
>
>Is this a bad thing or am I missing something here?

Pablo is correct: overloading and defining correct semantics yields
results different from the default-argument case.  Somebody who
cares about this case should enter a defect report when ISO begins
accepting them.

Nathan Myers
ncm@nospam.cantrip.org
---
[ 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: "Bradd W. Szonye" <bradds@concentric.net>
Date: 1998/01/09
Raw View
Pablo Halpern wrote in message <34b51b47.17335867@news.ma.ultranet.com>...
>Looking at my copy of CD2, I see the following constructor for
>basic_string declared as follows:
>
>basic_string(const basic_string& str, size_type pos = 0,
>             size_type n = npos, const Allocator& a = Allocator());
>
>Since all but the first argument are defaulted, this constitutes a copy
>constructor.  Given an allocator class where all instances are not
>equivalent, if you use this constructor as a copy constructor, the copy
>does not use the same allocator as the original. Is this what was
>intended?

I don't think that's really a problem. If you have a "copy always" string,
it's not a problem at all. If you have a "copy on write" implementation,
then the constructor body simply contains something like:

    if (a == str.get_allocator()) {
        /* set up copy-on-write */
    } else {
        /* use true copy */
    }

... which is what you have to do for differing allocators anyway. This might
be factored into a helper function that handles copying from
(possibly-different) allocators.
---
Bradd W. Szonye
bradds@concentric.net
http://www.concentric.net/~Bradds
---
[ 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
]