vector.size() and (signed) int

M

Mike Smith

Marcus said:
I am getting warnings when comparing a (regular) int to the value
returned from std::vector.size() in code similar to the following:

int i = //stuff
if (i >= vec.size())


The compiler gives me a "signed/unsigned mismatch" warning (I am using
the C++ compiler found in Visual Studio .NET 2003, which tells me that
the return type is a size_t). I get similar warnings when assigning the
return value of .size() to an int. However, even on Stroustrup's FAQ
<http://www.research.att.com/~bs/bs_faq2.html> he has:

for (int i = 0; i<v.size(); ++i)


which seems to me that it should be fine. In order to quiet the error,
I have casted the return value to an int:

if (i >= static_cast<int>(vec.size()))


Is this bad style? Is there a more elegant solution?

Why not just use size_t as the type of your loop index?
 
M

Mike Smith

Rolf said:
Howard wrote:




Actually, I'd say he should use int by default. unsigned types are only
useful in special cases. I actually don't understand why size_t is
unsigned.

Because a size can never be negative?
 
K

Kai-Uwe Bux

Richard said:
Kai-Uwe Bux said:
PS.: I have to admit, though, that the following idiom for counting down
to 0 in unsigned types looks funny [creating the impression of looping
forever]:

#include <iostream>

int main (void ) {

unsigned size = 10;
for ( unsigned i = size - 1; i < size; -- i ) {
std::cout << i << '\n';
}

}

That's not funny, it's *vile* (anagram of "evil"). Try this :

for (unsigned i = size; i-->0;)
{ //...
}

(Extra marks for working out the meaning of the emoticon -->0;)

Wow, so there is a legitimate use for postfix operators after all.


Thanks a bunch.

Kai-Uwe Bux

PS.: Of course the idiom you suggested is way superior: it works regardless
of whether i is signed or unsigned and is therefore *much* safer.
 
M

Marcus Kwok

Kai-Uwe Bux said:
Wow, so there is a legitimate use for postfix operators after all.

What about the old "copying C strings" idiom?

while (*src)
*dest++ = *src++;
 
K

Kai-Uwe Bux

Marcus said:
What about the old "copying C strings" idiom?

while (*src)
*dest++ = *src++;

For my taste that is just too much happening in one line. I prefer

while ( *src != 0 ) {
*dest = *src;
++dest;
++src;
}

I do not really consider avoiding {}-blocks and a few keystrokes as a
legitimate goal.


What struck me about

for (unsigned i = size; i-->0;)
{ //...
}

is that you cannot easily rewrite it to get rid of the postcrement while
keeping the for loop with its benefit of a local declaration.

[On second thought, I think you can:

for ( unsigned int = size; i > 0; ) {
--i;
...
}

Oh well, never mind. I just didn't see it.]


Best

Kai-Uwe Bux
 
R

Rui Maciel

msalters said:
For a number of reasons:

1. integer literals are precisely that, ints and not
std::vector<type>::size_type literals

vector<type>::size() returns a vector<type>::size_type. If we want to deal
with the size of a container, why shouldn't we use the type that the size
of the container is expressed with?

On top of that, as I mentioned in my previous post, a
vector<type>::size_type is a typedef of an unsigned integral type.

2. Readability of the code (which is why we need auto i = v.size() )

If readability of the code is an issue, than the best thing to do is to use
vector<type>::size_type. When someone is reading the code and stumbles on
the declaration

vector<type>::size_type i;

that person will imediately know that i will be used to handle the sizes of
a vector. That doesn't happen with a

int i;


Besides that, if there is an example to prove that we don't need an auto,
the example you pointed out is precisely it.

3. The actual int may be negative. E.g. the follwoing code can make
sense:
bool foo( int i, std::vector<int> v ) { return i > v.size(); }

and where, exactly, does a vector<type>::size_type makes that piece of code
not make sense? As far as I can see, it makes it as much, if not even more,
readable.

For i<=0 this should return false. Use unsigned and it will return true
instead.

being:
vector<type> v;
vector<type>::size_type i;

if i == 0 and v.size() == 0, foo does indeed returns false. If the purpose
of i is to compare sizes, I doubt that there is a need to express negative
sizes. Therefore, there isn't a need to use a signed number with that
particular piece of code.


So, exactly where is your problem with the vector<type>::size_type?


Best regards
Rui Maciel
 
B

Ben Hetland

Marcus said:
What about the old "copying C strings" idiom?

while (*src)
*dest++ = *src++;

Well, that fails to copy the entire "C string", doesn't it...

while (*dest++ = *src++);

would make the proper '\0' termination too.


-+-Ben-+-
 
M

Marcus Kwok

This is from a different thread, but I had asked this question in it and
then realized that I probably should have started a new thread for it.
I came up with the answer, and so I am posting it here. In case anyone
is interested, the solution was to pass the third argument (EOL
character) to std::getline().

Marcus Kwok said:
A somewhat related but tangential question, can anyone see a better
implementation for this function?

// setcol() sets the elements of the colv vector
// to the individual phrases found in input_record, which is tab-delimited.
//
// The column numbers start at 0.
//
// The number of columns found is returned.
int setcol(const std::string& input_record, std::vector<std::string>& colv)
{
std::string temp;

colv.clear();

typedef std::string::const_iterator CI;
CI end = input_record.end();
for (CI ci = input_record.begin(); ci != end; ++ci) {
if (*ci != '\t') {
temp += *ci;
}
else {
colv.push_back(temp);
temp.clear();
}
}
colv.push_back(temp);

return static_cast<int>(colv.size());
}


Originally I implemented it like the below, which I feel is much more
elegant, but I could not figure out how to get it to separate the
phrases only on tabs; it would delimit with any whitespace.

int setcol(const std::string& input_record, std::vector<std::string>& colv)
{
std::istringstream s(input_record);
std::string temp;

colv.clear();
while (s >> temp)
{
colv.push_back(temp);
}

return colv.size();
}

int setcol(const std::string& input_record, std::vector<std::string>& colv)
{
std::istringstream s(input_record);
std::string temp;

colv.clear();
while (std::getline(s, temp, '\t')) {
colv.push_back(temp);
}

return static_cast<int>(colv.size());
}
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,780
Messages
2,569,608
Members
45,241
Latest member
Lisa1997

Latest Threads

Top