Using operator new in function call and what the expr evaluates to

E

Eric Lilja

Consider this code that doesn't compile on two compilers I've tried:

void foo(const char *) {}

int main()
{
foo(new const char * ("bar"));
}

$ g++ -Wall -Wextra -std=c++98 -pedantic -g cpptest.cpp -o runme
cpptest.cpp: In function `int main()':
cpptest.cpp:7: error: cannot convert `const char**' to `const char*'
for argument `1' to `void foo(const char*)'

I came across this when I used a third party gui library and wanted to
associate a string with a gui control. The gui control stores some
integer type as its user value (that is normally a pointer) so I was
casting to that when calling my function and the compiler was happy
but I noticed the stored string was garbage when I retrieved it later.
And when I changed the signature of the function to take a pointer to
const char instead and only cast at the last possible instant I got an
error (and the explanation why the text I ended up storing was
garbage). It's just that I don't understand why that does not work.
 
G

Gianni Mariani

Eric said:
Consider this code that doesn't compile on two compilers I've tried:

void foo(const char *) {}

int main()
{
foo(new const char * ("bar"));
}

$ g++ -Wall -Wextra -std=c++98 -pedantic -g cpptest.cpp -o runme
cpptest.cpp: In function `int main()':
cpptest.cpp:7: error: cannot convert `const char**' to `const char*'
for argument `1' to `void foo(const char*)'

A literal string (i.e. "bar") evaluates to a const char [4], however a
special case in the C++ standard (which it should never have been placed
in the standard) is that a literal string can convert to a "char *"
without warning (which is irrelevant in this case but it's important to
be complete).

The compiler is telling you ...
cannot convert `const char**' to `const char*'

The way to do this is create a string factory - i.e.

const char * Factory( const char * v ) {
int len = strlen(v)+1
char * x = new char [len];
memcpy( x, v, len );
return x;
}

But then, who is responsible for calling delete[] on strings from
Factory() ?
I came across this when I used a third party gui library and wanted to
associate a string with a gui control.

Did the gui control delete[] the strings ? Did it make it's own copy ?
... The gui control stores some
integer type as its user value (that is normally a pointer) so I was
casting to that when calling my function and the compiler was happy
but I noticed the stored string was garbage when I retrieved it later.
And when I changed the signature of the function to take a pointer to
const char instead and only cast at the last possible instant I got an
error (and the explanation why the text I ended up storing was
garbage). It's just that I don't understand why that does not work.

Don't understand what does not work ?

If it's the "new const char * ("bar")" then it's because it's wrong,
plain and simple.

If it's because you have garbage, well, maybe it's because you do have
pointers to strings stored in your GUI thing that get modified at a
later time.

Is there any way your GUI thing can inform you that it's being deleted ?
That way you can hook into it to delete your string. Does your GUI
type have a virtual destructor ? If so, you can just derive from it and
provide your own destruction mechanism.
 
A

antonov84

void foo(const char *) {}

int main()
{
foo(new const char * ("bar"));
} .....

It's just that I don't understand why that does not work.

Well, when you do 'new int' you get 'int*' as a return type. When you
do 'new char*' you obviously get a 'char**' as a return type. For this
to compile put deref in front of new:

foo(* new const char *("bar"));

But that would make a pointer-size memory leak ;] and wouldnt copy
anything xept "bar" base address. So you could pass "bar" to your foo
with same success and no memory leaks ;].

if you dont like patternish factory talk, you can do this

foo( strcpy( new char [sizeof("bar")], "bar") );

but this looks no less ugly I think ;]

so maybe smthing like

template <int N>
const char* copystr(const char (&str)[N] )
{
return strcpy( new char[N], str );
}
....
foo(copystr("bar"));

but still dont forget to delete this all later.

Btw storing 'const char*' as 'int' is fine unless you're on 64 bit
platform (or some other weird platform where sizeof(const char*) !=
sizeof(int)). So maybe you just retreived it back wrong, or your code
have overwritten it due to some buffer overrun or smth else.
 
G

Gianni Mariani

void foo(const char *) {}

int main()
{
foo(new const char * ("bar"));
} ....

It's just that I don't understand why that does not work.

Well, when you do 'new int' you get 'int*' as a return type. When you
do 'new char*' you obviously get a 'char**' as a return type. For this
to compile put deref in front of new:

foo(* new const char *("bar"));

But that would make a pointer-size memory leak ;] and wouldnt copy
anything xept "bar" base address. So you could pass "bar" to your foo
with same success and no memory leaks ;].

if you dont like patternish factory talk, you can do this

foo( strcpy( new char [sizeof("bar")], "bar") );
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Pick your mistake.
but this looks no less ugly I think ;]

Too error prone.
so maybe smthing like

template <int N>
const char* copystr(const char (&str)[N] )
{
return strcpy( new char[N], str );
}

You have N. Why not use memcpy ?
...
foo(copystr("bar"));

but still dont forget to delete this all later.

Btw storing 'const char*' as 'int' is fine unless you're on 64 bit
platform (or some other weird platform where sizeof(const char*) !=
sizeof(int)). So maybe you just retreived it back wrong, or your code
have overwritten it due to some buffer overrun or smth else.

Yes, good point. The other option is to place your pointers in a vector
and manage the vector with new strings.
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top