1

I have a vector of strings which was created from parsing a config file. All the strings should be in the format key=value. I'd like to iterate over the vector, and use the putenv function to set an environment variable to the key-value pair.

The code:

for(auto it = settings.begin(); it != settings.end(); it++) {
      try {
         auto i = it - settings.begin();
         cout << i << endl;
         putenv(settings.at(i));
      } catch (...) {
         cout << "Config is not in the format key=value ... please correct" << endl;
      }
   }

This throws the error:

cannot convert ‘__gnu_cxx::__alloc_traits<std::allocator<std::basic_string<char> > >::value_type {aka std::basic_string<char>}’ to ‘char*’ for argument ‘1’ to ‘int putenv(char*)’

I'm very new to C++, and all these variable types and pointers are confusing me.

helloworld95
  • 366
  • 7
  • 17
  • it is a combination of https://stackoverflow.com/questions/347949/how-to-convert-a-stdstring-to-const-char-or-char plus this https://stackoverflow.com/questions/54279450/putenv-warning-with-c – 463035818_is_not_an_ai Feb 26 '20 at 21:43

2 Answers2

3

You're mixing C and C++ stuff.

  • Your vector contains C++ strings, std::string.
  • putenv is an "old" function expecting a pointer to a char buffer, i.e. a C-string.

Fortunately, std::string makes it easy to get one of those:

putenv(settings.at(i).c_str());
//                   ^^^^^^^^

However, there is still a problem there. putenv takes "ownership" of the buffer you give it, and expects it to last "forever". Yours won't; it'll only be there until the std::string is modified or destroyed. Not good enough!

Conventionally, we use C's strdup here to allocate a copy of the char buffer. It's then putenv's (or the OS's) responsibility to free it later.

putenv(strdup(settings.at(i).c_str()));
//     ^^^^^^^                      ^

Since putenv is not in the C or C++ standard, but is provided by POSIX, you should check the manpages for your operating system to make sure you're using it correctly.

Asteroids With Wings
  • 17,071
  • 2
  • 21
  • 35
  • not sure, but I found [`strdup`](https://en.cppreference.com/w/c/experimental/dynamic/strdup): "The returned pointer must be passed to free to avoid a memory leak." – 463035818_is_not_an_ai Feb 26 '20 at 21:46
  • 1
    @idclev463035818 which the C library will do at a later time, after `putenv()` takes ownership of the pointer. Although, not all implementations of `putenv()` take ownership, some make a copy of the `char` data instead, so check the documentation for your C library's particular implementation. – Remy Lebeau Feb 26 '20 at 22:23
  • Yes, exactly, that. – Asteroids With Wings Feb 26 '20 at 22:39
0

The error is caused by your call to putenv(), which expects a pointer to char's. Your vector contains C++ strings (std::string)...

You can try this:

for (auto setting : settings) {

     // ... putenv() is inconsistent across compilers, so use setenv() instead...         
     std::string key = item.substr( 0, item.find_first_of( "=" ) ) ;
     std::string val = item.substr( key.length()+1 ) ;

     if ( setenv( key.c_str(), val.c_str(), 1 ) != 0 ) {
        cerr << "setenv(" << key << ',' << val << ") has failed: " << strerror( errno ) << endl;
     }
}

From what I've read, putenv should be avoided in new code, and setenv should be used, as it makes a copy of its arguments, regardless of compiler version.

(setenv is in stdlib.h)