Invalid initialization of non-const reference

J

James Gregory

#include <cstdlib>
#include <cctype>
#include <string>

template <class Input_Iter>
inline int IterToInt(Input_Iter& iter, const Input_Iter& lineEnd) {
char tempArray[80] = {0};
for (int i = 0; std::isdigit(*iter) && iter != lineEnd && i != 80;
++i) {
tempArray = *iter;
++iter;
}
return atoi(tempArray);
}

int main(int argc, char* argv[]) {
if (argc > 1) {
std::string str = argv[1];
int a = IterToInt(str.begin(), str.end());
}

return 0;
}

A program I wrote does something similar to this and someone says that
it won't compile in GCC 3.4.2, which complains that:

error: invalid initialization of non-const reference of type
'__gnu_cxx::__normal_iterator<char*, std::basic_string<char,
std::char_traits<char>, std::allocator<char> > >&' from a temporary of
type '__gnu_cxx::__normal_iterator<char*, std::basic_string<char,
std::char_traits<char>, std::allocator<char> > >'

I don't use GCC, and so I hope that my test case above does actually
correctly demonstrate the problem. Should this fail? I didn't think
that my std::string str variable was temporary in the sense meant here?

Also, I realise that ideally IterToInt should use const_iterators, but
as far as I'm aware it isn't possible to do this in a generic way.

Thanks,

James
 
A

Alf P. Steinbach

* James Gregory:
#include <cstdlib>
#include <cctype>
#include <string>

template <class Input_Iter>
inline int IterToInt(Input_Iter& iter, const Input_Iter& lineEnd) {
char tempArray[80] = {0};
for (int i = 0; std::isdigit(*iter) && iter != lineEnd && i != 80;
++i) {
tempArray = *iter;
++iter;
}
return atoi(tempArray);
}

int main(int argc, char* argv[]) {
if (argc > 1) {
std::string str = argv[1];
int a = IterToInt(str.begin(), str.end());
}

return 0;
}

A program I wrote does something similar to this and someone says that
it won't compile in GCC 3.4.2, which complains that:

error: invalid initialization of non-const reference of type
'__gnu_cxx::__normal_iterator<char*, std::basic_string<char,
std::char_traits<char>, std::allocator<char> > >&' from a temporary of
type '__gnu_cxx::__normal_iterator<char*, std::basic_string<char,
std::char_traits<char>, std::allocator<char> > >'

I don't use GCC, and so I hope that my test case above does actually
correctly demonstrate the problem. Should this fail?
Yes.


I didn't think
that my std::string str variable was temporary in the sense meant here?


It isn't, but the iterators are temporary.

Also, I realise that ideally IterToInt should use const_iterators, but
as far as I'm aware it isn't possible to do this in a generic way.

Why do you pass by reference?
 
R

Rolf Magnus

James said:
#include <cstdlib>
#include <cctype>
#include <string>

template <class Input_Iter>
inline int IterToInt(Input_Iter& iter, const Input_Iter& lineEnd) {
char tempArray[80] = {0};
for (int i = 0; std::isdigit(*iter) && iter != lineEnd && i != 80;
++i) {
tempArray = *iter;
++iter;
}
return atoi(tempArray);
}

int main(int argc, char* argv[]) {
if (argc > 1) {
std::string str = argv[1];
int a = IterToInt(str.begin(), str.end());
}

return 0;
}

A program I wrote does something similar to this and someone says that
it won't compile in GCC 3.4.2, which complains that:

error: invalid initialization of non-const reference of type
'__gnu_cxx::__normal_iterator<char*, std::basic_string<char,
std::char_traits<char>, std::allocator<char> > >&' from a temporary of
type '__gnu_cxx::__normal_iterator<char*, std::basic_string<char,
std::char_traits<char>, std::allocator<char> > >'

I don't use GCC, and so I hope that my test case above does actually
correctly demonstrate the problem. Should this fail?
Yes.

I didn't think that my std::string str variable was temporary in the sense
meant here?


No. How could '__gnu_cxx::__normal_iterator<...>' be your std::string?
Anyway, your iterators are temopraries. str.begin() returns a temporary
iterator that you try to bind to a non-const reference in IterToInt. And
C++ doesn't allow this.
Also, I realise that ideally IterToInt should use const_iterators, but
as far as I'm aware it isn't possible to do this in a generic way.

It uses whatever you supply as argument.
 
J

James Gregory

Alf said:
* James Gregory:
#include <cstdlib>
#include <cctype>
#include <string>

template <class Input_Iter>
inline int IterToInt(Input_Iter& iter, const Input_Iter& lineEnd) {
char tempArray[80] = {0};
for (int i = 0; std::isdigit(*iter) && iter != lineEnd && i != 80;
++i) {
tempArray = *iter;
++iter;
}
return atoi(tempArray);
}

int main(int argc, char* argv[]) {
if (argc > 1) {
std::string str = argv[1];
int a = IterToInt(str.begin(), str.end());
}

return 0;
}

A program I wrote does something similar to this and someone says that
it won't compile in GCC 3.4.2, which complains that:

error: invalid initialization of non-const reference of type
'__gnu_cxx::__normal_iterator<char*, std::basic_string<char,
std::char_traits<char>, std::allocator<char> > >&' from a temporary of
type '__gnu_cxx::__normal_iterator<char*, std::basic_string<char,
std::char_traits<char>, std::allocator<char> > >'

I don't use GCC, and so I hope that my test case above does actually
correctly demonstrate the problem. Should this fail?
Yes.


I didn't think
that my std::string str variable was temporary in the sense meant
here?

It isn't, but the iterators are temporary.


Oh, yeah, doh, thanks.
Why do you pass by reference?

I guess iterators are small enough that passing them by value is as
fast/faster than passing them by reference? However, rather than
agonising over every argument to very function to decide whether it
would be faster to pass by value or by reference, I just go by a rule
of thumb that everything is passed by reference unless either a) it's a
built in type or b) I particularly don't want the original altered.

Thanks,

James
 
J

James Gregory

Plus of course if it's an inline function I realise that nothing
actually really gets passed by value in any case.
 
R

Rolf Magnus

James said:
* James Gregory:
#include <cstdlib>
#include <cctype>
#include <string>

template <class Input_Iter>
inline int IterToInt(Input_Iter& iter, const Input_Iter& lineEnd) {
char tempArray[80] = {0};
for (int i = 0; std::isdigit(*iter) && iter != lineEnd && i != 80;
++i) {
tempArray = *iter;
++iter;
}
return atoi(tempArray);
}

int main(int argc, char* argv[]) {
if (argc > 1) {
std::string str = argv[1];
int a = IterToInt(str.begin(), str.end());
}

return 0;
}

A program I wrote does something similar to this and someone says that
it won't compile in GCC 3.4.2, which complains that:

error: invalid initialization of non-const reference of type
'__gnu_cxx::__normal_iterator<char*, std::basic_string<char,
std::char_traits<char>, std::allocator<char> > >&' from a temporary of
type '__gnu_cxx::__normal_iterator<char*, std::basic_string<char,
std::char_traits<char>, std::allocator<char> > >'

I don't use GCC, and so I hope that my test case above does actually
correctly demonstrate the problem. Should this fail?
Yes.


I didn't think
that my std::string str variable was temporary in the sense meant
here?

It isn't, but the iterators are temporary.


Oh, yeah, doh, thanks.
Why do you pass by reference?

I guess iterators are small enough that passing them by value is as
fast/faster than passing them by reference?
Possibly.

However, rather than agonising over every argument to very function to
decide whether it would be faster to pass by value or by reference, I just
go by a rule of thumb that everything is passed by reference unless either
a) it's a built in type or b) I particularly don't want the original
altered.


This is not about performance, but about the fact that you _do_ alter the
original, which you are not allowed to if that original is a temporary.
Passing by value instead of by reference, you wouldn't have the problem you
have now, and in fact, it's common to pass iterators by value.
 

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,969
Messages
2,570,161
Members
46,705
Latest member
Stefkari24

Latest Threads

Top