So, the correct solution, hidden in an overloaded function, would be:
--Code:std::string dirname(const std::string &fullname)
{
char *tmp = strdup(fullname.c_str());
std::string result(dirname(tmp));
free tmp;
return result;
}
Mats
Printable View
So, the correct solution, hidden in an overloaded function, would be:
--Code:std::string dirname(const std::string &fullname)
{
char *tmp = strdup(fullname.c_str());
std::string result(dirname(tmp));
free tmp;
return result;
}
Mats
No, this leaks if std::string's constructor throws. The correct solution is
Code:vector<char> tmp(fullname.c_str(), fullname.c_str() + fullname.size() + 1);
return std::string(dirname(&tmp[0]));
Alternatively (more for my own practice, really):
But it's a bit messy.Code:std::string dirname(const std::string &fullname)
{
char *tmp = strdup(fullname.c_str());
try {
std::string result;
result = dirname(tmp);
}
catch(...)
{
free tmp;
throw;
}
free(tmp);
return result;
}
--
Mats
And your forgot to free the string in the non-error case.
I believe an auto_ptr may be in place?
I find the vector an even bigger hack, but one I'd prefer over mats's slightly longer code.
The best solution would just be to have a function that returns a buffer, char* or wchar_t* from std::string, however. But once again we are not as lucky.
I find it funny how the things in the standard library seems to be more oriented towards a C interface rather than a C++ interface (just look at the streams and how they only accept char* or wchar_t*), but with std::string, it's lacking a critical function for C compability.
Or, we can do it this way:
Despite what you may think, this is better than strdup, since strdup will do strlen first, then strcpy, where this code only does strncpy(). It may take 4 or 8KB of stack-space, but it eliminates the need to allocate dynamic memory (and thus handle problems with freeing it).Code:std::string dirname(const std::string &fullname)
{
char tmp[MAX_PATH+1];
strncpy(tmp, fullname.c_str(), MAX_PATH);
tmp[MAX_PATH] = 0; // Make sure there is a zero somewhere!
std::string result(dirname(tmp));
return result;
}
--
Mats
And "taking 4k of stack space" in a near-leaf function such as this only means modifying the stack pointer, so yeah, that's a good way.
Of course, MAX_PATH is Windows-only. There's a PATH_MAX in limits.h on POSIX.
What's a near-leaf function?
A leaf function is one that calls no other functions. A near-leaf function was an on-the-spot word creation meaning a function that calls only leaf functions.
It's a function that is near the "end" of a call-tree (main being the "root" of such a tree - at leas from the general programmers, as we don't normally consider the code that calls main() as part of the program, even if it technically is). A leaf-funciton is one that doesn't call any other functions, and a "near leaf" is one that only calls leaf-functions in itself. [Although, I suppose that the std::string::string(const char *) constructor is likely to call at least the new operator.
--
Mats
Here's a version that doesn't depend on strdup or the POSIX call:
Code:std::string dirname(const std::string & path)
{
std::string dir = path.substr(0, path.find_last_of("/"));
return ((dir != path) ? dir : std::string("."));
}