Topic: containers and "Assignable" (was: delete considered bad style!)
Author: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/01/29 Raw View
herbs@cntc.com (Herb Sutter) writes:
|> On 27 Jan 97 13:13:18 GMT, James Kanze
|> <james-albert.kanze@vx.cit.alcatel.fr> wrote:
|> >Does vector formally require assignment, or only copy construction?
|>
|> The type of all contained objects (in any container, not just vector)
|> must be both copy-constructible and assignable (see 23.1
|> [lib.container.requirements] paragraphs 3 and 4).
|>
|> (Aside: Whether the "assignable" requirement is worded correctly is
|> being discussed in the "Side effects in operators" thread.)
|>
|> >(I'll admit that without assignment, you cannot change any elements of
|> >the vector once the element has been constructed. But you should still
|> >be able to initialize it in an arbitrary fashion using push_back, and
|> >read it. Or am I missing something.)
|>
|> Of all the container requirements, the first relevant one is:
|>
|> expression: X::value_type
|> return type: T
|> requirement: T is Assignable
|>
|> (Aside: For completeness, shouldn't this one read
|> "T is Copy-Constructible and Assignable"?)
|>
|> However, I think the real stumbling block is the iterator requirements
|> (and possibly the requirements on other library elements mentioned in
|> the container and sequence requirements). For example, according to
|> 24.1.1 Table 73, input iterators have the following (perhaps
|> mis-specified?) requirement:
|>
|> operation: *r++
|> type: T
|> semantics: { T tmp = *r; ++r; return tmp; }
There is no assignment here, only copy construction.
|> which implicitly requires that T be assignable. If this were
|> rewritten as:
|>
|> semantics: { T tmp( *r ); ++r; return tmp; }
|>
|> then at least this particular requirement would not in and of itself
|> force T to be assignable.
|>
|> It may be possible to drop the "Assignable" requirement for objects
|> that can be put into vectors (for example), but the only way I can see
|> to do that would be to go through all the requirements of both
|> collections and sequences (since vector is a sequence) and make sure
|> that none of them: a) are specified in a way that requires assignment;
|> and b) mention any other library elements (like iterators) that are
|> specified in a way that requires assignment.
The main motivation for my question was that the current implementations
of vector, list, etc. do not use assignment except when you modify an
already contained element. Thus, from a practical point of view,
assignment is not necessary in such cases.
I can well understand the standard not wanting to enumerate too many
special cases, however, and it is certainly simpler (both to specify and
to understand) to group assignment and copy construction together.
--
James Kanze home: kanze@gabi-soft.fr +33 (0)1 39 55 85 62
office: kanze@vx.cit.alcatel.fr +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
-- Conseils en informatique industrielle --
---
[ 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: jpotter@falcon.lhup.edu (John E. Potter)
Date: 1997/01/29 Raw View
Herb Sutter (herbs@cntc.com) wrote:
: On 27 Jan 97 13:13:18 GMT, James Kanze
: <james-albert.kanze@vx.cit.alcatel.fr> wrote:
: >Does vector formally require assignment, or only copy construction?
[All containers require assignment for elements]
: However, I think the real stumbling block is the iterator requirements
: (and possibly the requirements on other library elements mentioned in
: the container and sequence requirements). For example, according to
: 24.1.1 Table 73, input iterators have the following (perhaps
: mis-specified?) requirement:
: operation: *r++
: type: T
: semantics: { T tmp = *r; ++r; return tmp; }
: which implicitly requires that T be assignable. If this were
: rewritten as:
: semantics: { T tmp( *r ); ++r; return tmp; }
: then at least this particular requirement would not in and of itself
: force T to be assignable.
See 8.5 Initializers. T tmp = *r is a construction not an assignment.
It's form is copy initialization; however, since the initializer (*r)
is the same type as tmp, it is treated in the same way as direct
initialization as specified in T tmp(*r). When the types are not the
same, the two forms are not equivalent; however, they are still
initializations not assignments.
class X { X(int); };
X a(5); // a.X::X(int)
X b(a); // b.X::X(X const&)
X c = a; // c.X::X(X const&) as used above
X d = 5; // d(X(5)) d.X::X(X const& X::X(int)) requires copy-ctor.
: It may be possible to drop the "Assignable" requirement for objects
: that can be put into vectors (for example), but the only way I can see
: to do that would be to go through all the requirements of both
: collections and sequences (since vector is a sequence) and make sure
: that none of them: a) are specified in a way that requires assignment;
: and b) mention any other library elements (like iterators) that are
: specified in a way that requires assignment.
The output iterator requires *r++ = t to be valid; however, this could
be met without T::operator=, possibly. Forward iterator requires
*a = t to be valid if X is mutable. This one seems to force assignable.
On the practical side, a vector of elements which could not be assigned
to would be of dubious value. Since all objects with the exception of
those classes which I explicitely declare an inaccessable assignment
operator have an operator=, I do not see much loss in requiring the
class to be assignable. Does anyone have an example of a non-assignable
class that they would put in a container?
John
---
[ 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: herbs@cntc.com (Herb Sutter)
Date: 1997/01/29 Raw View
On 29 Jan 1997 14:19:04 PST, jpotter@falcon.lhup.edu (John E. Potter)
wrote:
>: semantics: { T tmp = *r; ++r; return tmp; }
>: which implicitly requires that T be assignable.
(Mea culpa - it doesn't, of course.)
>: If this were
>: rewritten as:
>: semantics: { T tmp( *r ); ++r; return tmp; }
>: then at least this particular requirement would not in and of itself
>: force T to be assignable.
>
>See 8.5 Initializers. T tmp = *r is a construction not an assignment.
>It's form is copy initialization; however, since the initializer (*r)
>is the same type as tmp, it is treated in the same way as direct
>initialization as specified in T tmp(*r). When the types are not the
Also 12.6.1, which lists some examples. You're right that my comment was
messed up, and James was kind enough to point it out to me in email earlier
today.
>The output iterator requires *r++ = t to be valid; however, this could
>be met without T::operator=, possibly. Forward iterator requires
>*a = t to be valid if X is mutable. This one seems to force assignable.
This is a better example of what I was trying to illustrate, and seems to
answer my question about whether it was possible to drop the Assignable
requirement for containers and sequences.
>On the practical side, a vector of elements which could not be assigned
>to would be of dubious value. Since all objects with the exception of
>those classes which I explicitely declare an inaccessable assignment
>operator have an operator=, I do not see much loss in requiring the
>class to be assignable. Does anyone have an example of a non-assignable
>class that they would put in a container?
I can't speak for James, who started this thought, but I had in mind the
case of containers which are assembled once (e.g., by some program
initialisation) and are thereafter conceptually const for the lifetime of
the program, being used only for reference purposes. I have several such
structures in one of my current systems, and they are implemented with map
and list containers, but at the moment all of the objects stored in them
happen to have assignable type.
---
Herb Sutter (herbs@cntc.com)
Current Network Technologies Corp.
3100 Ridgeway, Suite 42, Mississauga ON Canada L5L 5M5
Tel 416-805-9088 Fax 905-608-2611
[ 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: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/01/30 Raw View
herbs@cntc.com (Herb Sutter) writes:
|> >On the practical side, a vector of elements which could not be assigned
|> >to would be of dubious value. Since all objects with the exception of
|> >those classes which I explicitely declare an inaccessable assignment
|> >operator have an operator=, I do not see much loss in requiring the
|> >class to be assignable. Does anyone have an example of a non-assignable
|> >class that they would put in a container?
|>
|> I can't speak for James, who started this thought, but I had in mind the
|> case of containers which are assembled once (e.g., by some program
|> initialisation) and are thereafter conceptually const for the lifetime of
|> the program, being used only for reference purposes. I have several such
|> structures in one of my current systems, and they are implemented with map
|> and list containers, but at the moment all of the objects stored in them
|> happen to have assignable type.
Actually, I initially asked the question simply to know the formal
answer, not because I had a particular implementation in mind. It does
occur to me, however, that one might wish to read configuration data
from a disk file (inserting them into a set, or into a vector by means
of push_back); such data would never never be modified once created, and
could potentially be non-assignable.
Of course, if you know that the assignment operator will never be used,
there is a simple work-around. Derive from the non-assignable class,
and provide an operator= which simply calls abort. The problem is,
IMHO, that unless the standard says something about it, you really
cannot be assured that assignment is not used. (Given that default
construction is not required, it is difficult to imagine how an
implementation could use assignment in push_back, for example. But
there is no guarantee from the standard that it doesn't.)
--
James Kanze home: kanze@gabi-soft.fr +33 (0)1 39 55 85 62
office: kanze@vx.cit.alcatel.fr +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
-- Conseils en informatique industrielle --
---
[ 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: jpotter@falcon.lhup.edu (John E. Potter)
Date: 1997/02/02 Raw View
James Kanze (james-albert.kanze@vx.cit.alcatel.fr) wrote:
: herbs@cntc.com (Herb Sutter) writes:
: |> >Does anyone have an example of a non-assignable
: |> >class that they would put in a container?
: |> I can't speak for James, who started this thought, but I had in
: |> mind the case of containers which are assembled once (e.g., by
: |> some program initialisation) and are thereafter conceptually
: |> const for the lifetime of the program, being used only for
: |> reference purposes. I have several such structures in one of my
: |> current systems, and they are implemented with map and list
: |> containers, but at the moment all of the objects stored in them
: |> happen to have assignable type.
: Actually, I initially asked the question simply to know the formal
: answer, not because I had a particular implementation in mind. It does
: occur to me, however, that one might wish to read configuration data
: from a disk file (inserting them into a set, or into a vector by means
: of push_back); such data would never never be modified once created, and
: could potentially be non-assignable.
My question was about an object which was copy-constructable yet not
assignable. We know that the item for a container must be copy-
constructable. Are there any examples of a useful class with these
properties? If not, the assignable requirement is really no burden.
There are examples of classes which are neither, as James has noted in
clcm. These classes may not be used with STL.
I do have an example; however, it is explicitely not an object. There
is no default construction or assignment and there is copy construction
as well as conversion construction. Reference! Get rid of the
assignment requirement and all containers will be required to support
reference types. That alone should be enough to keep the assignment
requirement in the standard. Containers of references are not easy
to create. And, of course, they would not fit into the algorithm and
iterator framework of STL.
: Of course, if you know that the assignment operator will never be used,
: there is a simple work-around. Derive from the non-assignable class,
: and provide an operator= which simply calls abort. The problem is,
: IMHO, that unless the standard says something about it, you really
: cannot be assured that assignment is not used. (Given that default
: construction is not required, it is difficult to imagine how an
: implementation could use assignment in push_back, for example. But
: there is no guarantee from the standard that it doesn't.)
Almost. The constructors take an object parameter with a default value
of T(). The draft points out that this should be implemented as two
constructors so that a user can supply a default object always and not
need the default constructor. Given this, vector can copy construct
all tiems when growing and then overwrite them in push_back. It is
also easy to see how assignment would be used in erase.
I have tried to make sence of the requirements and have the following
conclusions. I had to work backwards to get any results.
There are no requirements placed on algorithms. Algorithms use
iterators; therefor, iterators are required to have attributes
which support the algorithms. Iterators are over containers;
therefor, containers must supply iterators and have attributes
which support the iterators. Containers contain items; therefor,
the items must have attributes which suport the container.
As a user, if my objects support the requirements, I get all of the
containers and all of the algorithms. There is nothing in the
draft to tell me what I can use with less than all of the
requirements. As you point out above, it should be possible to
implement vector::push_back without assignment; however, there is
no such requirement in the draft. It might work on some
implementation but it is not portable. It is not even a quality
of implementation issue. Finer grained requirements would be
nice, maybe in another ten years, but not now.
Comments?
John
---
[ 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: jpotter@falcon.lhup.edu (John E. Potter)
Date: 1997/02/03 Raw View
James Kanze (james-albert.kanze@vx.cit.alcatel.fr) wrote:
: Of course, if you know that the assignment operator will never be used,
: there is a simple work-around. Derive from the non-assignable class,
: and provide an operator= which simply calls abort. The problem is,
: IMHO, that unless the standard says something about it, you really
: cannot be assured that assignment is not used. (Given that default
: construction is not required, it is difficult to imagine how an
: implementation could use assignment in push_back, for example. But
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
: there is no guarantee from the standard that it doesn't.)
After my prior post, I thought about and investigated this. Since
push_back(x) is a special case of insert(iter, x) where iter is
end, it would make sence to implement push_back that way. Sure
enough, g++ (HP clone) does. And of course insert uses copy_backward
to make room for the new item. And that uses assignment. The loop
is executed zero times for push_back; however, it must still compile.
I guess that this is reasonable and we best have "nice" classes if
we want to use the library.
John
---
[ 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: herbs@cntc.com (Herb Sutter)
Date: 1997/01/28 Raw View
On 27 Jan 97 13:13:18 GMT, James Kanze
<james-albert.kanze@vx.cit.alcatel.fr> wrote:
>Does vector formally require assignment, or only copy construction?
The type of all contained objects (in any container, not just vector)
must be both copy-constructible and assignable (see 23.1
[lib.container.requirements] paragraphs 3 and 4).
(Aside: Whether the "assignable" requirement is worded correctly is
being discussed in the "Side effects in operators" thread.)
>(I'll admit that without assignment, you cannot change any elements of
>the vector once the element has been constructed. But you should still
>be able to initialize it in an arbitrary fashion using push_back, and
>read it. Or am I missing something.)
Of all the container requirements, the first relevant one is:
expression: X::value_type
return type: T
requirement: T is Assignable
(Aside: For completeness, shouldn't this one read
"T is Copy-Constructible and Assignable"?)
However, I think the real stumbling block is the iterator requirements
(and possibly the requirements on other library elements mentioned in
the container and sequence requirements). For example, according to
24.1.1 Table 73, input iterators have the following (perhaps
mis-specified?) requirement:
operation: *r++
type: T
semantics: { T tmp = *r; ++r; return tmp; }
which implicitly requires that T be assignable. If this were
rewritten as:
semantics: { T tmp( *r ); ++r; return tmp; }
then at least this particular requirement would not in and of itself
force T to be assignable.
It may be possible to drop the "Assignable" requirement for objects
that can be put into vectors (for example), but the only way I can see
to do that would be to go through all the requirements of both
collections and sequences (since vector is a sequence) and make sure
that none of them: a) are specified in a way that requires assignment;
and b) mention any other library elements (like iterators) that are
specified in a way that requires assignment.
---
Herb Sutter (herbs@cntc.com)
Current Network Technologies Corp.
3100 Ridgeway, Suite 42, Mississauga ON Canada L5L 5M5
Tel 416-805-9088 Fax 905-608-2611
---
[ 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 ]