tags:

views:

358

answers:

5

I see C's getcwd via: man 3 cwd

I suspect C++ has a similar one, that could return me a std::string .

If so, what is it called, and where can I find it's documentation?

Thanks!

+3  A: 

std::string's constructor can safely take a char* as a parameter. Surprisingly there's a windows version too.

Edit: actually it's a little more complicated:

std::string get_working_path()
{
   char temp[MAXPATHLEN];
   return ( getcwd(temp, MAXPATHLEN) ? std::string( temp ) : std::string("") );
}

Memory is no problem -- temp is a stack based buffer, and the std::string constructor does a copy. Probably you could do it in one go, but I don't think the standard would guarantee that.

About memory allocation, via POSIX:

The getcwd() function shall place an absolute pathname of the current working directory in the array pointed to by buf, and return buf. The pathname copied to the array shall contain no components that are symbolic links. The size argument is the size in bytes of the character array pointed to by the buf argument. If buf is a null pointer, the behavior of getcwd() is unspecified.

Kornel Kisielewicz
Both this answer and Liranuna's comment use `getcwd` as a no-argument function, yet the documentation I see shows two parameters. Am I reading the wrong docs?
Rob Kennedy
is the char * automatigally freed? or does this give me a memory leak?
anon
@anon no, the resulting char* is `malloc` ed and should be `free` d after creating a std::string from it.
Bill
@Kornel Please use `MAXPATHLEN` instead of your magic number(128) ;)
AraK
@Rob - good point, I expanded the answer.
Kornel Kisielewicz
@Arak, defines are evil! xP
Kornel Kisielewicz
@Bill, that's a non-standard extension, as far as I can tell. Linux, Mac, and Windows all implement it, which may or may not be "portable enough."
Rob Kennedy
@Bill, the POSIX specification explicitly states that data is copied, not allocated, hence no freeing is needed.
Kornel Kisielewicz
Sorry, I was looking at the no-parameter version before the edit changed it to take a buffer. If you use the no-parameter version (or the non-standard version that mallocs if given a NULL buffer) then you will need to use free.
Bill
-1 Potential buffer overflow. Bad code. ( will allocate std::string based on garbage in temp if getcwd fails, garbage may not be nul terminated; you need to check return value from ::getcwd and throw on error )
Pete Kirkham
@Pete, exceptions are not a solution that can be used always - refrain from wanting to throw everywhere. However the error checking was ommited for verbosity as usual in such cases. Where do you see a buffer overflow?
Kornel Kisielewicz
If an error occurs, then the contents of temp are undefined. As you were creating a string using the single argument constructor expecting a nul terminated string, the constructor could scan off the end before you hit a nul. Hence, buffer (read) overflow. Your edited code does not have this issue, but may cause weird behaviour in whatever is using the return value if it does fail, unless the client tests for an empty string. Personally, I wouldn't wrap the posix function at all, and let the client code test the documented POSIX result rather than testing for empty.
Pete Kirkham
+2  A: 

All C functions are also C++ functions. If you need a std::string, just create one from the char* that getcwd gets for you.

Rob Kennedy
+1  A: 

You'll need to just write a little wrapper.

std::string getcwd_string( void ) {
   char buff[PATH_MAX];
   getcwd( buff, PATH_MAX );
   std::string cwd( buff );
   return cwd;
}
Brian Gianforcaro
You should use PATH_MAX instead of a magic number.
Bill
@Bill thanks, learn something new every day.
Brian Gianforcaro
+5  A: 

Ok, I'm answering even though you already have accepted an answer.

An even better way than to wrap the getcwd call would be to use boost::filesystem, where you get a path object from the current_path() function. The Boost filesystem library allows you to do lots of other useful stuff that you would otherwise need to do a lot of string parsing to do, like checking if files/directories exist, get parent path, make paths complete etcetera. Check it out, it is portable as well - which a lot of the string parsing code one would otherwise use likely won't be.

villintehaspam
+1  A: 

Let's try and rewrite this simple C call as C++:

std::string get_working_path()
{
    char temp [ PATH_MAX ];

    if ( getcwd(temp, PATH_MAX) == 0) 
        return std::string ( temp );

    int error = errno;

    switch ( error ) {
        // EINVAL can't happen - size argument > 0

        // PATH_MAX includes the terminating nul, 
        // so ERANGE should not be returned

        case EACCES:
            throw std::runtime_error("Access denied");

        case ENOMEM:
            // I'm not sure whether this can happen or not 
            throw std::runtime_error("Insufficient storage");

        default: {
            std::ostringstream str;
            str << "Unrecognised error" << error;
            throw std::runtime_error(str.str());
        }
    }
}

The thing is, when wrapping a library function in another function you have to assume that all the functionality should be exposed, because a library does not know what will be calling it. So you have to handle the error cases rather than just swallowing them or hoping they won't happen.

It's usually better to let the client code just call the library function, and deal with the error at that point - the client code probably doesn't care why the error occurred, and so only has to handle the pass/fail case, rather than all the error codes.

Pete Kirkham