Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

std::vectpr "Replace" Function?

134 views
Skip to first unread message

MikeCopeland

unread,
Oct 16, 2014, 7:29:24 PM10/16/14
to
Is there no "replace" function for a std::vector? I know that I can
modify a specific vector object by using the .at() operator or the []
indexing, but that's not really what I after. I have the following
declarations:

struct Display
{
int offset;
char dCode;
string p1, p3, p8;
} dispWork;
vector<Display> dispVect;
vector<Display>::iterator dIter;

for(dIter = dispVect.begin(); dIter != dispVect.end(); dIter++)
{
if(condition1) dIter = dispVect.erase(dIter);
else if(condition2) dispVect.replace(dispWork); //????
}

After populating the vector, I wish to use the iterator to walk
through the vector tp delete or change certain elements. I don't want
to use [] indexing during this process because I'm also erasing/removing
elements. This combined processing will fail by invalidating the
iterator when I delete elements, so I'd prefer to use some "replace"
function for the vector elements I'm saving and changing.
There doesn't seem to be any STL function that accomodates my needs
here...or am I wrong? Please advise. TIA


---
This email is free from viruses and malware because avast! Antivirus protection is active.
http://www.avast.com

Juha Nieminen

unread,
Oct 17, 2014, 2:50:01 AM10/17/14
to
MikeCopeland <mrc...@cox.net> wrote:
> for(dIter = dispVect.begin(); dIter != dispVect.end(); dIter++)
> {
> if(condition1) dIter = dispVect.erase(dIter);
> else if(condition2) dispVect.replace(dispWork); //????
> }

You mean like *dIter = dispWork; ?

Btw, your loop skips the elements next to the ones that are erased.
If the last element is erased, it will skip to the element after
the end, which is just bad.

--- news://freenews.netfront.net/ - complaints: ne...@netfront.net ---

Chris Vine

unread,
Oct 17, 2014, 7:30:16 AM10/17/14
to
On Thu, 16 Oct 2014 16:29:06 -0700
MikeCopeland <mrc...@cox.net> wrote:
> Is there no "replace" function for a std::vector? I know that I
> can modify a specific vector object by using the .at() operator or
> the [] indexing, but that's not really what I after. I have the
> following declarations:
>
> struct Display
> {
> int offset;
> char dCode;
> string p1, p3, p8;
> } dispWork;
> vector<Display> dispVect;
> vector<Display>::iterator dIter;
>
> for(dIter = dispVect.begin(); dIter != dispVect.end(); dIter++)
> {
> if(condition1) dIter = dispVect.erase(dIter);
> else if(condition2) dispVect.replace(dispWork); //????
> }
>
> After populating the vector, I wish to use the iterator to walk
> through the vector tp delete or change certain elements. I don't
> want to use [] indexing during this process because I'm also
> erasing/removing elements. This combined processing will fail by
> invalidating the iterator when I delete elements, so I'd prefer to
> use some "replace" function for the vector elements I'm saving and
> changing. There doesn't seem to be any STL function that accomodates
> my needs here...or am I wrong? Please advise. TIA

You cannot erase an element of a vector as if it were a list, for
obvious reasons (I hope), so the approach in your code doesn't work.
You have to move elements within the vector instead. One approach is to
apply std::remove()/std::remove_if() to do this and then apply
std::replace/std::replace_if() to what you have left. Note that
std::remove/std::remove_if() partitions your vector rather than resizing
it. If you want to resize it you have to do that yourself afterwards.

You could write your own algorithm to combine the operations if
profiling really shows that to be necessary. If a particular element
meets the criterion for erasure you increment the read iterator without
incrementing the write iterator. If it meets the criterion for
changing, you change when writing to the write iterator. If neither,
once at least one erasure has been made, you move assign the value
referenced by the read iterator to the element referenced by the write
iterator. And so on until your read iterator is at the end. You can
improve the readability of the algorithm by calling std::find_if() first
to find the first position at which either criterion is met - until
then there is nothing to do.

Chris

MikeCopeland

unread,
Oct 17, 2014, 10:39:32 AM10/17/14
to
In article <m1qe6c$2va4$1...@adenine.netfront.net>, nos...@thanks.invalid
says...
>
> > for(dIter = dispVect.begin(); dIter != dispVect.end(); dIter++)
> > {
> > if(condition1) dIter = dispVect.erase(dIter);
> > else if(condition2) dispVect.replace(dispWork); //????
> > }
>
> You mean like *dIter = dispWork; ?
^^^^^^^^^^^^^^^^^^
This won't compile. I first tried that, as I use it with other STL
containers. However, it doesn't compile for my std::vector. (Perhaps I
have some other error nearby...<sigh>)
>
> Btw, your loop skips the elements next to the ones that are erased.
> If the last element is erased, it will skip to the element after
> the end, which is just bad.

Yes, I see that. I should use a "while(dIter != dispVect.end())"
loop, right? 8<}}

Victor Bazarov

unread,
Oct 17, 2014, 10:50:17 AM10/17/14
to
On 10/16/2014 7:29 PM, MikeCopeland wrote:
> Is there no "replace" function for a std::vector? I know that I can
> modify a specific vector object by using the .at() operator or the []
> indexing, but that's not really what I after. I have the following
> declarations:
>
> struct Display
> {
> int offset;
> char dCode;
> string p1, p3, p8;
> } dispWork;
> vector<Display> dispVect;
> vector<Display>::iterator dIter;
>
> for(dIter = dispVect.begin(); dIter != dispVect.end(); dIter++)

the increment should not happen if you erase. Move it inside the
loop body and only perform it if *not* condition1.

> {
> if(condition1) dIter = dispVect.erase(dIter);
> else if(condition2) dispVect.replace(dispWork); //????
> }
>
> After populating the vector, I wish to use the iterator to walk
> through the vector tp delete or change certain elements. I don't want
> to use [] indexing during this process because I'm also erasing/removing
> elements.

...incorrectly!

> This combined processing will fail by invalidating the
> iterator when I delete elements, so I'd prefer to use some "replace"
> function for the vector elements I'm saving and changing.

What Juha suggested *is* how you replace. Make sure the rest is OK.

> There doesn't seem to be any STL function that accomodates my needs
> here...or am I wrong? Please advise. TIA

V
--
I do not respond to top-posted replies, please don't ask

Juha Nieminen

unread,
Oct 17, 2014, 11:29:04 AM10/17/14
to
MikeCopeland <mrc...@cox.net> wrote:
>> You mean like *dIter = dispWork; ?
> ^^^^^^^^^^^^^^^^^^
> This won't compile. I first tried that, as I use it with other STL
> containers. However, it doesn't compile for my std::vector. (Perhaps I
> have some other error nearby...<sigh>)

What the compiler tells you is relevant. You usually don't have to *guess*
what the problem is because the compiler is telling you.

Drew Lawson

unread,
Oct 17, 2014, 1:44:27 PM10/17/14
to
In article <m1rcjj$orp$1...@adenine.netfront.net>
Juha Nieminen <nos...@thanks.invalid> writes:
>MikeCopeland <mrc...@cox.net> wrote:
>>> You mean like *dIter = dispWork; ?
>> ^^^^^^^^^^^^^^^^^^
>> This won't compile. I first tried that, as I use it with other STL
>> containers. However, it doesn't compile for my std::vector. (Perhaps I
>> have some other error nearby...<sigh>)
>
>What the compiler tells you is relevant. You usually don't have to *guess*
>what the problem is because the compiler is telling you.

Unfortunately, when the error involves templated types, the error
message is so long and nested that reading it is very difficult.

When I get a compile error in STL using code, my first response is
to get the line number and stare at the code. Usually I can spot
something in much less time than it would take to read a 800 character
message that is drowning in angle brackets.

At least that is my experience with Visual Studio and gcc.

--
Drew Lawson | "But the senator, while insisting he was not
| intoxicated, could not explain his nudity."

MikeCopeland

unread,
Oct 17, 2014, 2:48:37 PM10/17/14
to
In article <m1rcjj$orp$1...@adenine.netfront.net>, nos...@thanks.invalid
says...
>
> >> You mean like *dIter = dispWork; ?
> > ^^^^^^^^^^^^^^^^^^
> > This won't compile. I first tried that, as I use it with other STL
> > containers. However, it doesn't compile for my std::vector. (Perhaps I
> > have some other error nearby...<sigh>)
>
> What the compiler tells you is relevant. You usually don't have to *guess*
> what the problem is because the compiler is telling you.

Sorry, it's M$ Visual Studio Express 2013.
I'll fire it up and get the specific error info. My apologies...

MikeCopeland

unread,
Oct 17, 2014, 3:29:54 PM10/17/14
to
In article <m1qe6c$2va4$1...@adenine.netfront.net>, nos...@thanks.invalid
says...
>
> > for(dIter = dispVect.begin(); dIter != dispVect.end(); dIter++)
> > {
> > if(condition1) dIter = dispVect.erase(dIter);
> > else if(condition2) dispVect.replace(dispWork); //????
> > }
>
> You mean like *dIter = dispWork; ?
> ^^^^^^^^^^^^^^^^^^
Yes, this works as you suggested. My problems lay elsewhere... 8<{{
Thanks, everyone!

Robert Wessel

unread,
Oct 18, 2014, 12:14:35 AM10/18/14
to
On Fri, 17 Oct 2014 17:44:11 +0000 (UTC), dr...@furrfu.invalid (Drew
Lawson) wrote:

>In article <m1rcjj$orp$1...@adenine.netfront.net>
> Juha Nieminen <nos...@thanks.invalid> writes:
>>MikeCopeland <mrc...@cox.net> wrote:
>>>> You mean like *dIter = dispWork; ?
>>> ^^^^^^^^^^^^^^^^^^
>>> This won't compile. I first tried that, as I use it with other STL
>>> containers. However, it doesn't compile for my std::vector. (Perhaps I
>>> have some other error nearby...<sigh>)
>>
>>What the compiler tells you is relevant. You usually don't have to *guess*
>>what the problem is because the compiler is telling you.
>
>Unfortunately, when the error involves templated types, the error
>message is so long and nested that reading it is very difficult.
>
>When I get a compile error in STL using code, my first response is
>to get the line number and stare at the code. Usually I can spot
>something in much less time than it would take to read a 800 character
>message that is drowning in angle brackets.
>
>At least that is my experience with Visual Studio and gcc.


I've often though some better formatting of that sort of message would
make them considerably more readable. Just a decent indenting scheme
to should the nesting of references ought to go a long way. One could
even imagine a fancy graphical representation, although there are the
(obvious) reasons for wanting to keep the error messages reasonably
pure text.

MikeCopeland

unread,
Oct 18, 2014, 1:04:09 AM10/18/14
to
> > > for(dIter = dispVect.begin(); dIter != dispVect.end(); dIter++)
> > > {
> > > if(condition1) dIter = dispVect.erase(dIter);
> > > else if(condition2) dispVect.replace(dispWork); //????
> > > }
> >
> > You mean like *dIter = dispWork; ?
> ^^^^^^^^^^^^^^^^^^
> This won't compile. I first tried that, as I use it with other STL
> containers. However, it doesn't compile for my std::vector. (Perhaps I
> have some other error nearby...<sigh>)

Yes, I had another problem: in my actual code I had declared dIter as a "const_iterator". This (is one of the) causes for the C2678 error I was getting.
Thus, even though I tried using the above code, with my particular declaration the compile errored...

Juha Nieminen

unread,
Oct 20, 2014, 9:09:37 AM10/20/14
to
Drew Lawson <dr...@furrfu.invalid> wrote:
> Unfortunately, when the error involves templated types, the error
> message is so long and nested that reading it is very difficult.

Ignore the type, look at what the compiler is saying about it.

Drew Lawson

unread,
Oct 20, 2014, 11:36:44 AM10/20/14
to
In article <m231i0$276p$1...@adenine.netfront.net>
Juha Nieminen <nos...@thanks.invalid> writes:
>Drew Lawson <dr...@furrfu.invalid> wrote:
>> Unfortunately, when the error involves templated types, the error
>> message is so long and nested that reading it is very difficult.
>
>Ignore the type, look at what the compiler is saying about it.

Dude, "what the compiler is saying about it" is in the *middle* of
that 800 character message.

This is what g++ gives me when I use a non-const iterator on a const
vector<string> (linebreaks added for sanity, the original is 2 lines):

foo.cc:11: error: no match for 'operator=' in 'it = foo.std::vector<_Tp,
_Alloc>::begin [with _Tp = std::basic_string<char,
std::char_traits<char>, std::allocator<char> >, _Alloc =
std::allocator<std::basic_string<char, std::char_traits<char>,
std::allocator<char> > >]()'
/usr/include/c++/4.2/bits/stl_iterator.h:637: note: candidates
are: __gnu_cxx::__normal_iterator<std::basic_string<char,
std::char_traits<char>, std::allocator<char> >*,
std::vector<std::basic_string<char, std::char_traits<char>,
std::allocator<char> >, std::allocator<std::basic_string<char,
std::char_traits<char>, std::allocator<char> > > > >&
__gnu_cxx::__normal_iterator<std::basic_string<char,
std::char_traits<char>, std::allocator<char> >*,
std::vector<std::basic_string<char, std::char_traits<char>,
std::allocator<char> >, std::allocator<std::basic_string<char,
std::char_traits<char>, std::allocator<char> > > > >::operator=(const
__gnu_cxx::__normal_iterator<std::basic_string<char,
std::char_traits<char>, std::allocator<char> >*,
std::vector<std::basic_string<char, std::char_traits<char>,
std::allocator<char> >, std::allocator<std::basic_string<char,
std::char_traits<char>, std::allocator<char> > > > >&)

Readability is not optimal.

You can imagine what happens when the problem code is using
map<string, map<string, string> >

--
Drew Lawson | I told them we had learned to change
| our swordblades into plows.
| I told them they should learn from us
| what should I tell them now?

Paavo Helde

unread,
Oct 20, 2014, 12:22:37 PM10/20/14
to
dr...@furrfu.invalid (Drew Lawson) wrote in
news:m23a60$2oet$1...@raid.furrfu.com:

> In article <m231i0$276p$1...@adenine.netfront.net>
> Juha Nieminen <nos...@thanks.invalid> writes:
>>Drew Lawson <dr...@furrfu.invalid> wrote:
>>> Unfortunately, when the error involves templated types, the error
>>> message is so long and nested that reading it is very difficult.
>>
>>Ignore the type, look at what the compiler is saying about it.
>
> Dude, "what the compiler is saying about it" is in the *middle* of
> that 800 character message.
>
> This is what g++ gives me when I use a non-const iterator on a const
> vector<string> (linebreaks added for sanity, the original is 2 lines):
>
> foo.cc:11: error: no match for 'operator=' in 'it =

Here the compiler explicitly tells you in the beginning of the error
message: "no match for 'operator='". That's all you need, the rest of the
line noise can be ignored. It tells me an assignment did not work
somewhere. If I look at the culprit line and it looks otherwise kosher,
then the reason is most probably const-non-const mixup. At least it has
been so in 100% of cases I have seen this error for my code.

Yes, the error messages could be better, but they are actually helpful -
if you know what to look for.

Cheers
Paavo

Drew Lawson

unread,
Oct 20, 2014, 1:59:30 PM10/20/14
to
In article <XnsA3CCC5141ECB4m...@216.196.109.131>
Paavo Helde <myfir...@osa.pri.ee> writes:
>dr...@furrfu.invalid (Drew Lawson) wrote in
>news:m23a60$2oet$1...@raid.furrfu.com:
>
>> Dude, "what the compiler is saying about it" is in the *middle* of
>> that 800 character message.
>>
>> This is what g++ gives me when I use a non-const iterator on a const
>> vector<string> (linebreaks added for sanity, the original is 2 lines):
>>
>> foo.cc:11: error: no match for 'operator=' in 'it =
>
>Here the compiler explicitly tells you in the beginning of the error
>message: "no match for 'operator='". That's all you need, the rest of the
>line noise can be ignored. It tells me an assignment did not work
>somewhere. If I look at the culprit line and it looks otherwise kosher,
>then the reason is most probably const-non-const mixup. At least it has
>been so in 100% of cases I have seen this error for my code.

As I said originally, I just look at the line number and go to the
code. The line number tells me 99.99% of what that hideous message
does.

>Yes, the error messages could be better, but they are actually helpful -
>if you know what to look for.

This started with a post by a newbie. How in the world is "read the
error message" a useful response to someone who clearly does not
"know what to look for"?

My point was *exactly* that it is difficult to know what part of
such a message is the part that isn't gibberish.


After decades of alleged improvement, I don't think I should need
to search that hard for such a common and predictable error. "Cannot
assign to a non-const iterator" would help oodles, and cut out a
lot of confused newbie postings.

I realize this is a toolset problem, not a language problem. I'd
appreciate hearing about any C++ compilers that don't spew line
noise for cases like this.

--
Drew Lawson | If dreams were thunder,
| and lightning was desire,
| This old house would have burnt down
| a long time ago

Paavo Helde

unread,
Oct 20, 2014, 3:01:16 PM10/20/14
to
dr...@furrfu.invalid (Drew Lawson) wrote in
news:m23ihk$2s1d$1...@raid.furrfu.com:
> I realize this is a toolset problem, not a language problem. I'd
> appreciate hearing about any C++ compilers that don't spew line
> noise for cases like this.

I did a little experimentation with online compilers. The program is
here:

#include <vector>
#include <string>
int main() {
std::vector<std::string> abc;
abc.push_back("a");
std::vector<std::string>::const_iterator it = abc.begin();
*it = "b";
}

The error messages I got are below. It appears Intel's icc is actually
producing the most helpful message.

---------------------
icc 13.0:

/tmp/gcc-explorer-compiler114920-17793-151o21n/example.cpp(7): error: no
operator "=" matches these operands

operand types are: const std::string = const char [2]


---------------------
gcc 4.9.0:

/tmp/gcc-explorer-compiler114920-29276-1xukbcf/example.cpp: In function
‘int main()’:

7 : error: passing ‘const std::basic_string’ as ‘this’ argument of
‘std::basic_string<_CharT, _Traits, _Alloc>& std::basic_string<_CharT,
_Traits, _Alloc>::operator=(const _CharT*) [with _CharT = char; _Traits =
std::char_traits; _Alloc = std::allocator]’ discards qualifiers [-
fpermissive]

---------------------
clang 3.4.1

7 : error: no viable overloaded '='

*it = "b";

~~~ ^ ~~~

/usr/lib/gcc/x86_64-linux-
gnu/4.8/../../../../include/c++/4.8/bits/basic_string.h:546:7: note:
candidate function not viable: 'this' argument has type 'const
std::basic_string<char>', but method is not marked const

operator=(const basic_string& __str)

^

/usr/lib/gcc/x86_64-linux-
gnu/4.8/../../../../include/c++/4.8/bits/basic_string.h:554:7: note:
candidate function not viable: 'this' argument has type 'const
std::basic_string<char>', but method is not marked const

operator=(const _CharT* __s)

^

/usr/lib/gcc/x86_64-linux-
gnu/4.8/../../../../include/c++/4.8/bits/basic_string.h:565:7: note:
candidate function not viable: 'this' argument has type 'const
std::basic_string<char>', but method is not marked const

operator=(_CharT __c)

^

-----------------------------

MSVC 2012:

test.cpp(7): error C2678: binary '=' : no operator found which takes a
left-hand operand of type 'const std::basic_string<_Elem,_Traits,
_Alloc>' (or there is no acceptable conversion)
with
[
_Elem=char,
_Traits=std::char_traits<char>,
_Alloc=std::allocator<char>
]
C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include
\xstring(912): could be 'std::basic_string<_Elem,_Traits,_Alloc>
&std::basic_string<_Elem,_Traits,_Alloc>::operator =(std::basic_string
<_Elem,_Traits,_Alloc> &&) throw()'
with
[
_Elem=char,
_Traits=std::char_traits<char>,
_Alloc=std::allocator<char>
]
C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include
\xstring(969): or 'std::basic_string<_Elem,_Traits,_Alloc>
&std::basic_string<_Elem,_Traits,_Alloc>::operator =(const
std::basic_string<_Elem,_Traits,_Alloc> &)'
with
[
_Elem=char,
_Traits=std::char_traits<char>,
_Alloc=std::allocator<char>
]
C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include
\xstring(987): or 'std::basic_string<_Elem,_Traits,_Alloc>
&std::basic_string<_Elem,_Traits,_Alloc>::operator =(const _Elem *)'
with
[
_Elem=char,
_Traits=std::char_traits<char>,
_Alloc=std::allocator<char>
]
C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include
\xstring(992): or 'std::basic_string<_Elem,_Traits,_Alloc>
&std::basic_string<_Elem,_Traits,_Alloc>::operator =(_Elem)'
with
[
_Elem=char,
_Traits=std::char_traits<char>,
_Alloc=std::allocator<char>
]
while trying to match the argument list '(const
std::basic_string<_Elem,_Traits,_Alloc>, const char [2])'
with
[
_Elem=char,
_Traits=std::char_traits<char>,
_Alloc=std::allocator<char>
]

-------------------------------


0 new messages