473,387 Members | 1,561 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

unexpected unique_copy constness issue

I was trying to come up with a neat STL-heavy response to this thread
about multimaps:

http://groups.google.com/group/comp....e6796296b79797

My implementation involved using unique_copy to uniquify the set of
keys. However, the compiler (gcc 4.0.2) complains because it's trying
to (internally) use

std::pair<const int, int> & std::pair<const int,
int>::operator=(std::pair<const int,int> const&)

which it has synthesized. The code is as follows:

#include <map>
#include <algorithm>
#include <vector>

using namespace std;

typedef pair<int, int> value;

bool cmp(value const& lhs, value const& rhs)
{
return lhs.first == rhs.first;
}

int main()
{
typedef map<int, int> m_t;
m_t m;

vector<value> v;

copy(m.begin(),
m.end(),
back_inserter<vector<value> >(v));

unique_copy(m.begin(),
m.end(),
back_inserter<vector<value> >(v),
cmp);

return EXIT_SUCCESS;
}

Note that the call to copy() proceeds without problem. I can
understand why the map holds std::pair<const int, int> rather than
std::pair<int, int>, but I don't see why it would need to assign to a
value of that type to do unique_copy. Especially because copy() works
just fine... anyone got an idea here?

Luke

May 26 '06 #1
8 1636
Ram
Luke Meyers wrote:
I was trying to come up with a neat STL-heavy response to this thread
about multimaps:

http://groups.google.com/group/comp....e6796296b79797

My implementation involved using unique_copy to uniquify the set of
keys. However, the compiler (gcc 4.0.2) complains because it's trying
to (internally) use

std::pair<const int, int> & std::pair<const int,
int>::operator=(std::pair<const int,int> const&)

which it has synthesized. The code is as follows:

#include <map>
#include <algorithm>
#include <vector>

using namespace std;

typedef pair<int, int> value;

bool cmp(value const& lhs, value const& rhs)
{
return lhs.first == rhs.first;
}

int main()
{
typedef map<int, int> m_t;
m_t m;

vector<value> v;

copy(m.begin(),
m.end(),
back_inserter<vector<value> >(v));

unique_copy(m.begin(),
m.end(),
back_inserter<vector<value> >(v),
cmp);

return EXIT_SUCCESS;
}

Note that the call to copy() proceeds without problem. I can
understand why the map holds std::pair<const int, int> rather than
std::pair<int, int>, but I don't see why it would need to assign to a
value of that type to do unique_copy. Especially because copy() works
just fine... anyone got an idea here?


A look at the unique_copy implementation gives the clue. I am using g++
3.4.2 and here is how it looks

template<typename _InputIterator, typename _OutputIterator,
typename _BinaryPredicate>
_OutputIterator
__unique_copy(_InputIterator __first, _InputIterator __last,
_OutputIterator __result,
_BinaryPredicate __binary_pred,
output_iterator_tag)
{
// concept requirements -- iterators already checked

__glibcxx_function_requires(_BinaryPredicateConcep t<_BinaryPredicate,
typename iterator_traits<_InputIterator>::value_type,
typename iterator_traits<_InputIterator>::value_type>)

typename iterator_traits<_InputIterator>::value_type __value =
*__first;
*__result = __value;
while (++__first != __last)
if (!__binary_pred(__value, *__first))
{
__value = *__first;
*++__result = __value;
}
return ++__result;
}

The offending line is

__value = *__first;

in the inner loop which tries to assign to a variable of type
InputIterator::value_type. That fails as its a std::pair<const int,
int> whose *first* is *const int*.

Ram

May 26 '06 #2
Ram wrote:
typename iterator_traits<_InputIterator>::value_type __value =
*__first;
*__result = __value;
while (++__first != __last)
if (!__binary_pred(__value, *__first))
{
__value = *__first;
*++__result = __value;
}

The offending line is

__value = *__first;

in the inner loop which tries to assign to a variable of type
InputIterator::value_type. That fails as its a std::pair<const int,
int> whose *first* is *const int*.


Is this correct, though? It strikes me as an irritating and
unnecessary restriction, and while I'm loath to suggest that the gcc
STL implementation is wrong, I find nothing more plausible. I believe
it's correct for map to store pair<const int, int>. It seems like
unique_copy should be able to operate within the constraint of a
non-assignable value type, so long as that type is copy-constructible.
It may not be as efficient, but that could perhaps be addressed by
template specialization. Am I missing something here?

Luke

May 26 '06 #3
Luke Meyers wrote:
I was trying to come up with a neat STL-heavy response to this thread
about multimaps:

http://groups.google.com/group/comp....e6796296b79797
My implementation involved using unique_copy to uniquify the set of
keys. However, the compiler (gcc 4.0.2) complains because it's trying
to (internally) use

std::pair<const int, int> & std::pair<const int,
int>::operator=(std::pair<const int,int> const&)

which it has synthesized. The code is as follows:

#include <map>
#include <algorithm>
#include <vector>

using namespace std;

typedef pair<int, int> value;

bool cmp(value const& lhs, value const& rhs)
{
return lhs.first == rhs.first;
}

int main()
{
typedef map<int, int> m_t;
m_t m;

vector<value> v;

copy(m.begin(),
m.end(),
back_inserter<vector<value> >(v));

unique_copy(m.begin(),
m.end(),
back_inserter<vector<value> >(v),
cmp);

return EXIT_SUCCESS;
}

Note that the call to copy() proceeds without problem. I can
understand why the map holds std::pair<const int, int> rather than
std::pair<int, int>, but I don't see why it would need to assign to a
value of that type to do unique_copy. Especially because copy() works
just fine... anyone got an idea here?


I had a look at the g++ implementation of unique_copy. Apparently, it uses a
variable of type iterator_traits<InIter>::value_type to keep track of runs
of equal elements. This is reasonable since input iterators have very weak
guarantees. This variable is updated using assignment. That is where the
error message comes from.

Here is a draft for a less restrictive unique_copy. It only uses
initialization of the variable:

template < typename InIter, typename OutIter, typename BinPred >
OutIter unique_copy ( InIter from, InIter to, OutIter where, BinPred eq ) {
typedef typename std::iterator_traits<InIter>::value_type value_type;
while ( from != to ) {
value_type last_value = *from++;
*where++ = last_value;
//skip loop:
while ( ( from != to ) && eq( last_value, *from ) ) {
++from;
}
}
return ( where );
}

Warning, this is totally untested code.

Also, I am not sure whether the g++ STL is in error: unique_copy is listed
under the modifying sequence operations, but the effects section for that
algorithm does not list any modification of the input sequence. I think
that [25/5] should then imply that the value_type is not supposed to be
modifyable.
Best

Kai-Uwe Bux
May 26 '06 #4
> > typename iterator_traits<_InputIterator>::value_type __value =
*__first;
*__result = __value;
while (++__first != __last)
if (!__binary_pred(__value, *__first))
{
__value = *__first;
*++__result = __value;
}

The offending line is

__value = *__first;

in the inner loop which tries to assign to a variable of type
InputIterator::value_type. That fails as its a std::pair<const int,
int> whose *first* is *const int*.


Is this correct, though? It strikes me as an irritating and
unnecessary restriction, and while I'm loath to suggest that the gcc
STL implementation is wrong, I find nothing more plausible. I believe
it's correct for map to store pair<const int, int>. It seems like
unique_copy should be able to operate within the constraint of a
non-assignable value type, so long as that type is copy-constructible.
It may not be as efficient, but that could perhaps be addressed by
template specialization. Am I missing something here?


I too wouldn't like to suggest that the implementation is wrong. But
its possible for the implementation to be less restrictive (to be able
to work with non-assignable value type). Instead of saving the values
one could save the iterator position for doing comparisons. Here's the
modified code (original commented out)-

// typename iterator_traits<_InputIterator>::value_type __value =
*__first;
_InputIterator __previous = __first;
// *__result = __value;
*__result = *__previous;
while (++__first != __last) {
// if (!__binary_pred(__value, *__first))
if (!__binary_pred(*__previous, *__first))
{
// __value = *__first;
__previous = __first;
// *++__result = __value;
*++__result = *__previous;
}
}

That puts the requirement of _InputIterator to be assignable though.
Not sure whether this might be a restriction. Also Kai-Uwe Bux
suggested an alternate implementation. Time to raise a bug-report with
g++ maintainers? :-)

Ram

May 26 '06 #5
ra********@gmail.com wrote:
> typename iterator_traits<_InputIterator>::value_type __value =
> *__first;
> *__result = __value;
> while (++__first != __last)
> if (!__binary_pred(__value, *__first))
> {
> __value = *__first;
> *++__result = __value;
> }
>
> The offending line is
>
> __value = *__first;
>
> in the inner loop which tries to assign to a variable of type
> InputIterator::value_type. That fails as its a std::pair<const int,
> int> whose *first* is *const int*.
Is this correct, though? It strikes me as an irritating and
unnecessary restriction, and while I'm loath to suggest that the gcc
STL implementation is wrong, I find nothing more plausible. I believe
it's correct for map to store pair<const int, int>. It seems like
unique_copy should be able to operate within the constraint of a
non-assignable value type, so long as that type is copy-constructible.
It may not be as efficient, but that could perhaps be addressed by
template specialization. Am I missing something here?


I too wouldn't like to suggest that the implementation is wrong. But
its possible for the implementation to be less restrictive (to be able
to work with non-assignable value type). Instead of saving the values
one could save the iterator position for doing comparisons. Here's the
modified code (original commented out)-

_InputIterator __previous = __first;
*__result = *__previous;
while (++__first != __last) {
if (!__binary_pred(*__previous, *__first))
This will *not* work: __previous is invalidated by incrementing __first. The
postconditions for ++r on input iterator are stated as follows [24, Table
72]:

++r X&
pre: r is dereferenceable.
post: r is dereferenceable or r is past-the-end.
post: any copies of the previous value of r are no longer
required either to be dereferenceable or to be in the domain of ==

{
__previous = __first;
*++__result = *__previous;
}
}

That puts the requirement of _InputIterator to be assignable though.
Not sure whether this might be a restriction.


No, input iterators are assignable. However, you cannot use stored values of
an iterator that has been incremented for dereferencing.
Best

Kai-Uwe Bux

May 26 '06 #6
Ram
[...]
_InputIterator __previous = __first;
*__result = *__previous;
while (++__first != __last) {
if (!__binary_pred(*__previous, *__first))


This will *not* work: __previous is invalidated by incrementing __first. The
postconditions for ++r on input iterator are stated as follows [24, Table
72]:

++r X&
pre: r is dereferenceable.
post: r is dereferenceable or r is past-the-end.
post: any copies of the previous value of r are no longer
required either to be dereferenceable or to be in the domain of ==

{
__previous = __first;
*++__result = *__previous;
}
}

That puts the requirement of _InputIterator to be assignable though.
Not sure whether this might be a restriction.


No, input iterators are assignable. However, you cannot use stored values of
an iterator that has been incremented for dereferencing.


Oh yes. It won't work with iterators which wrap an input stream for
example..

May 26 '06 #7
In article <11**********************@j33g2000cwa.googlegroups .com>,
"Luke Meyers" <n.***********@gmail.com> wrote:
Is this correct, though? It strikes me as an irritating and
unnecessary restriction, and while I'm loath to suggest that the gcc
STL implementation is wrong, I find nothing more plausible. I believe
it's correct for map to store pair<const int, int>. It seems like
unique_copy should be able to operate within the constraint of a
non-assignable value type, so long as that type is copy-constructible.
It may not be as efficient, but that could perhaps be addressed by
template specialization. Am I missing something here?


The standard is in error. I've attempted to correct it (twice now):

http://www.open-std.org/jtc1/sc22/wg...ctive.html#538

The corrected standard will have the effect of making gcc incorrect, and
your example code conforming. However gcc has already been corrected
(not sure which release) so that it will be conforming by the time this
defect report becomes normative.

-Howard
May 26 '06 #8
Howard Hinnant wrote:
In article <11**********************@j33g2000cwa.googlegroups .com>,
"Luke Meyers" <n.***********@gmail.com> wrote:
Am I missing something here? The standard is in error.


Ah, sweet vindication!
I've attempted to correct it (twice now):

http://www.open-std.org/jtc1/sc22/wg...ctive.html#538
Thank you very much for providing this response, and for Fighting the
Good Fight.
The corrected standard will have the effect of making gcc incorrect, and
your example code conforming. However gcc has already been corrected
(not sure which release) so that it will be conforming by the time this
defect report becomes normative.


Fantastic. I'll see if a gcc update does the trick.

Cheers,
Luke

May 27 '06 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Richard Hayden | last post by:
Hi, I understand such pointers as 'const int* const ip' and 'const int* ip' etc., but I'm getting confused when seeing things like 'const int* const* ip' (i.e. with two or more asterisks)....
15
by: Trevor Lango | last post by:
I want to be able to cast away the constness of a private member variable in a member function of a class. I have the private data member declared as follows: const double x; I have an...
8
by: Srini | last post by:
Hello all, I was just wondering about this. A const member function guarantees constness of the object within the function body. But there's no way for a member function to guarantee the...
7
by: Olav | last post by:
Hi I wonder if it is possible to have templates expand based on constness, something like: template<typename A, typename B>copy( A &a, B &b); becoming: copy( const class AClass &a, class...
5
by: Vijayakrishna Pondala | last post by:
Hi, We are using the following error randomly, when accessing a webservice method/servlet hosted on JBoss application server: The underlying connection was closed: An unexpected error occurred...
14
by: PengYu.UT | last post by:
In the following program, I want an iterator contain pointer pointing to constant object not const pointer. If it is possible would you please let me know how to do it? #include...
2
by: Laurent Deniau | last post by:
I am looking for the "cleanest" way to cast away the constness of a pointee in C89, something like const_cast<T*>() in C++. Actually, I am using: #define CONST_CAST(typename,value) \ (((union {...
13
by: bintom | last post by:
I ran the following simple code in C++ and got unexpected results: float f = 139.4; cout << f; Output: 139.399994;
13
by: Javier | last post by:
Hello, I have some cuestions about constness with standard containers and pointers. Supose I have a list of pointers to some class B: std::list< B * list; I have readed that constness in...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.