Re: strange compiler message

From: Neil Zanella (nzanella_at_cs.mun.ca)
Date: 08/13/04


Date: 13 Aug 2004 11:13:15 -0700

Tobias Güntner <fatbull@users.sourceforge.net> wrote in message news:<cfbl36

> > void trim_whitespace(string& str);
> > int main()
> > {
> > char *blah = malloc(12);
> > strcpy(blah, " blah blah ");
> > trim_whitespace(blah);
> > return 0;
> > }
>
> This code is illegal and should not compile for two reasons:
> 1) malloc returns void* which cannot be converted to char* (but I guess
> it's just a typo)

You're right, this in fact seems to be one difference between C and C++:

In C you can say "char *blah = malloc(12);",
but in C++ you must explicitly use a cast or
the compiler will complain.

> 2) in the call to trim_whitespace, a temporary std::string has to be
> constructed and bound to a reference to non-const string. Constructing a
> string is allowed, but binding the temporary string to a reference to
> non-const is not (see 13.3.3.1.4/3).
> Actually the standard also says that references to non-const cannot be
> bound to r-values [13.3.2/3], but IMHO that's more or less the same in
> our context (although I'm not a language lawyer ;) )

I see what you mean now: consider the following code:

#include <iostream>
#include <cstring>
#include <string>

void foo(std::string &str) { // not allowed because C++ won't convert a
                               // temporary to a nonconst reference on a
                               // function call: must use the following
                               // signature instead
//void foo(const std::string &str) {
  std::cout << str << std::endl;
}

int main() {
  char *blah = static_cast<char *>(malloc(22));
  strcpy(blah, " blah blah ");
  foo(blah);
}

When I use the wrong signature the compiler issues the following error:

$ g++ hello.cpp
hello.cpp: In function `int main ()':
hello.cpp:16: could not convert `blah' to `string &'
hello.cpp:5: in passing argument 1 of `foo (string &)'

> As I said, it's _not_ allowed and you've provided a nice example that
> shows why it isn't allowed ;)

Thanks. ;)
 
> because IMHO the restriction has been placed to prevent subtle bugs that
> can only occur under very specific circumstances.
>
> There is no problem with functions that take references to const - It
> clearly states "dear function, take this object and do with it what you
> like, but don't change it", whereas reference to non-const says "take
> this object and do with it what you like; you may even change it".
> In the latter case, the compiler cannot be sure if the programmer wanted
> to modify a) the original object or b) the temporary object that had to
> be created for conversion. These two things are completely different!

In other words it's all there to prevent programming errors due to the
programmer not checking signatures: to prevent the situation where the
programmer expects the passed in parameter to be modified when in fact
something constructed from it ends up being modified.

All of this because C++ introduces the concept of calling a constructor
on a parameter to a function. The fact that such constructor may
do a copy on the passed in argument means that the resulting
constructed object may not alter the origninal object when
acted upon by some code.

Fair enough. It seems like nothing more than a design decision.
The following is legal because it does not make use of the
"construction on function call" as described above.

#include <iostream>
#include <cstring>
#include <string>

void foo(std::string &str) {
  std::cout << str << std::endl;
}

int main() {
  char *blah = static_cast<char *>(malloc(22));
  strcpy(blah, " blah blah ");
  std::string s(blah);
  foo(s);
}

The following is also disallowed, by design decision: the C++ designers
figured that since a temporary is being passed in good coding practice
dictates that the programmer ought to be make foo const. (?)

#include <iostream>
#include <cstring>
#include <string>

void foo(std::string &str) {
  std::cout << str << std::endl;
}

int main() {
  char *blah = static_cast<char *>(malloc(22));
  strcpy(blah, " blah blah ");
  foo(std::string(blah));
}



Relevant Pages

  • Re: Working with strings in c++
    ... int i; ... The use of a copy constructor to initialise myStr from the temporary ... compiler to do it the two-step way, or the compiler is allowed to refuse to ... explicit MyString(const char* arg) ...
    (microsoft.public.vc.language)
  • Re: Requesting sample code!
    ... int m_i1, m_i2; ... then a constructor is not made automatically by the compiler. ...
    (microsoft.public.vc.language)
  • Re: Effeciency
    ... As lame as his class is, the compiler ... > distinguish between my class and an int. ... the presence of the constructor from unsinged int means ... check with an actual integral type (via a typedef) for your release mode ...
    (comp.lang.cpp)
  • Re: operator function
    ... Well I guess you are talking about a copy constructor right? ... The compiler is talking about the result of the addition, ... an int. ... > operator returns a Setting object. ...
    (alt.comp.lang.learn.c-cpp)
  • Re: It Pays to Enrich Your C Skills
    ... Check if you can score a perfect 10 (without using a compiler). ... int main{ ... struct bitfield { ... out if it is a negative integer constant or a constant expression ...
    (comp.lang.c.moderated)