Reputation: 311
I was wondering whether there is a way in C++ that a "string" (in whatever representation) that get's passed into a function can be assumed to be a valid string by that function.
I'm very new to C/C++ but so far as I can see, in C that question is answered by default because there is no other way und you just know that you have to check:
#include <stdio.h>
void foo(const char *str)
{
if (str)
printf("%s\n", str);
}
int main()
{
char *name = "Jack";
foo(name);
return 0;
}
But since C++ offers additional stuff like references I was wondering whether one could write foo() in such a way that it doesn't have to check. I tried it like this:
#include <iostream>
#include <string>
void foo(const std::string &str)
{
std::cout << str << std::endl;
}
int main(void)
{
std::string name = "Jack";
foo(name);
std::string *str = NULL;
foo(*str);
return 0;
}
But as you can see I can fool foo() to run into a SegFault. So, I guess you just always have to check, no matter what?
EDIT #1:
Okay, first of all thanks for all your answers and future answers, they are all much appreciated!
So to sum up what I learned so far:
There is no syntactic way in C++ to write a function defintion to eliminate misuse by the actual function call.
Is that correct? If so, I see my original question as answered.
So now I trying to write foo() as defensive as possible, so that no matter how much you treat foo() like a dog, it just won't produce a SegFault.
In C I would now write it like this (assuming short-circut evaluation):
#include <stdio.h>
void foo(const char *str, const size_t len)
{
if (str && (str[len - 1] == '\0'))
printf("%s\n", str);
}
int main()
{
char *name = "Jack";
foo(name, 5);
/* possible mistakes, but foo can handle them */
foo(name, 4);
foo(name, -1);
foo(NULL, 5);
return 0;
}
And in C++ I'm trying this:
#include <iostream>
#include <string>
void foo(const std::string &str)
{
if (&str)
std::cout << str << std::endl;
}
int main(void)
{
std::string name = "Jack";
foo(name);
std::string *str = NULL;
foo(*str);
return 0;
}
...but I'm not sure if that is in any approriate or what one would, could or should do with exceptions in this case.
What do you think? If you can't prevent misuse by syntax you gotta increase the precautions?
Upvotes: 3
Views: 140
Reputation: 103733
std::string *str = NULL;
foo(*str);
This is undefined behavior, on the part of the caller. Not your problem. So no, you(the writer of foo
) don't have to check.
Even in C, with the pointer, you don't necessarily have to check. You just have to document. "The argument must point to a valid null-terminated string. If it is not, the call is undefined behavior." -- If the user passes a NULL, that is, again, their problem. This is done all the time. If it wasn't, you'd have wasteful call chains checking the validity of the pointer at every level like this:
void foo(const char * s)
{
if (s)
printf("%s", s);
}
void bar(const char * s)
{
if (s)
foo(s);
}
void baz(const char * s)
{
if (s)
bar(s);
}
Upvotes: 9
Reputation: 22634
No, you're not right.
In the second code, undefined behaviour happens when you dereference your pointer, before you ever get to your function.
This is not a problem of your function. Inside your function, with the second signature you can always assume that you have a valid string, which makes it superior to the first one.
Upvotes: 2