I'm trying to learn c++ for a project and I'm having a bit of a problem with string concatenation.
My application consists of the application itself and a statically linked library project.
In the library I've defined a type representing a path on the file system, acting as a wrapper around a std::string path literal.
I've defined a function to concatenate the parent folder's path with the (user supplied) name of the file/folder itself, adding in path separators as needed.
The function code looks like this:
std::string normalize(std::string parentPath, const std::string& name) {
if (name.empty()) {
return parentPath;
} else {
parentPath.reserve(parentPath.length()+name.length()+1);
if (*name.begin() != Path::SEGMENT_SEPARATOR) {
parentPath.append(1,Path::SEGMENT_SEPARATOR);
}
if(*name.rbegin() != Path::SEGMENT_SEPARATOR){
parentPath.append(name);
}else{
parentPath.append(name.begin(), --name.end());
}
return parentPath;
}
}
(Path::SEGMENT_SEPARATOR is a const char '/')
The problem is this: every call to string::append does not seem to do anything.
I debugged the function with gdb and the content of parentPath does not change.
I checked the user input, looking for '/0' or other invalid characters in the input ("name"), but did not find anything wrong with it.
When I moved the exact same function to the application project (out of the library project), it did work as expected (with the same input).
Both projects are compiled using the same toolset (GCC 4.8.1 and are using the C++11 dialect) and the same compiler parameters (all warnings on, no warnings received in code).
Is there anything in my code which could break string::append in this fashion ?
EDIT: the function is called from:
Path::Path(const Path& parent, const std::string& name) : path_(normalize(parent.path_, name)) { }
Path::Path(const Path& parent, const char* name) : Path(parent, std::string(name)) {}
Which in turn is called from(header file):
extern const IO::Path CONFIG_PATH;
extern const IO::Path LANGUAGES_PATH;
With definition in cpp file:
const IO::Path Game::CONFIG_PATH{"conf"};
const IO::Path Game::LOG_PATH{CONFIG_PATH,"log"};
Inspection of the LOG_PATH object shows its 'path_' member value as just "conf" instead of "conf/log" as expected.
Can I be sure CONFIG_PATH is initialized before LOG_PATH, can this be the problem?
EDIT:
I read up the standard and it seems you can't rely on any initialization order for globals.
This means the declarations of CONFIG_PATH and LOG_PATH are obviously errors and I should probably wrap them into a function call like this:
const IO::Path &getConfigPath(){
static IO::Path config{"conf"};
return config;
};
Can this be why the string appending fails ?
Ignoring the reason of your problem, I strongly suggest you to use this simple version:
std::string normalize(std::string parentPath, const std::string& name)
{
if (name.empty())
return parentPath;
else
{
if (name.front() != Path::SEGMENT_SEPARATOR)
parentPath += Path::SEGMENT_SEPARATOR;
if(name.back() != Path::SEGMENT_SEPARATOR)
parentPath += name;
else
parentPath.append(name.begin(), name.end()-1);
return parentPath;
}
}
You may use
string str1, str2, strFinal;
strFinal = str1 + "some static string" + str2;
Which I think you should
Just for your reference:
std::string normalize(std::string parentPath, const std::string& name)
{
if (name.empty())
return parentPath;
else
{
if (name[0] != '/')
parentPath += '/';
if(name[name.length()-1] != '/')
parentPath += name;
else
parentPath.append(name.begin(), name.end()-1);
return parentPath;
}
}
Here's an SSCCE demonstrating that your function works correctly. Problem is in code that you are not showing us.
The problem is almost certainly some configuration issue (mismatch in compiler options, linker options or preprocessor defs between the two projects) as it does not occur when the I merge the two projects into one.
Thanks for the comments on the concatenation function: I'll be rewriting it to a more readable form later on.
Thanks to everyone for the helpful comments.
EDIT: found the problem.
A preprocessor #define used to switch on linux dependent implementation of certain members of Path (mainly function creating new dirs and files) was switched on in main project but not in library. This probably caused the problem when the library was linked. Works like a charm now.
Related
I'd like to have access to the $HOME environment variable in a C++ program that I'm writing. If I were writing code in C, I'd just use the getenv() function, but I was wondering if there was a better way to do it. Here's the code that I have so far:
std::string get_env_var( std::string const & key ) {
char * val;
val = getenv( key.c_str() );
std::string retval = "";
if (val != NULL) {
retval = val;
}
return retval;
}
Should I use getenv() to access environment variables in C++? Are there any problems that I'm likely to run into that I can avoid with a little bit of knowledge?
There is nothing wrong with using getenv() in C++. It is defined by stdlib.h, or if you prefer the standard library implementation, you can include cstdlib and access the function via the std:: namespace (i.e., std::getenv()). Absolutely nothing wrong with this. In fact, if you are concerned about portability, either of these two versions is preferred.
If you are not concerned about portability and you are using managed C++, you can use the .NET equivalent - System::Environment::GetEnvironmentVariable(). If you want the non-.NET equivalent for Windows, you can simply use the GetEnvironmentVariable() Win32 function.
I would just refactor the code a little bit:
std::string getEnvVar( std::string const & key ) const
{
char * val = getenv( key.c_str() );
return val == NULL ? std::string("") : std::string(val);
}
If you are on Windows you can use the Win32 API GetEnvironmentVariable
On other linux/unix based systems use getenv
Why use GetEnvironmentVariable in Windows, from MSDN getenv:
getenv operates only on the data
structures accessible to the run-time
library and not on the environment
"segment" created for the process by
the operating system. Therefore,
programs that use the envp argument to
main or wmain may retrieve invalid
information.
And from MSDN GetEnvironment:
This function can retrieve either a
system environment variable or a user
environment variable.
In c++ you have to use std::getenv and #include <cstdlib>
A version of #Vlad's answer with some error checking and which distinguishes empty from missing values:
inline std::string get_env(const char* key) {
if (key == nullptr) {
throw std::invalid_argument("Null pointer passed as environment variable name");
}
if (*key == '\0') {
throw std::invalid_argument("Value requested for the empty-name environment variable");
}
const char* ev_val = getenv(key);
if (ev_val == nullptr) {
throw std::runtime_error("Environment variable not defined");
}
return std::string(ev_val);
}
Notes:
You could also replace the use of exceptions in the above with an std::optional<std::string> or, in the future, with an std::expected (if that ends up being standardized).
I've chosen safety over informativity here, by not concatenating the key into the what-string of the exception. If you make the alternative choice, try and limit copying from key to within reason (e.g. 100 characters? 200 characters?), and I'd also check these characters are printable, and sanitize those characters.
Yes, I know this is an old thread!
Still, common mistakes are, by definition, not new. :-)
The only reasons I see for not just using std::getenv(), would be to add a known default or to adopt common pattern/API in a framework. I would also avoid exceptions in this case (not generally though) simply because a non-value return is often enough a valid response for an environment variable. Adding the complexity of handling exceptions is counter-intuitive.
This is basically what I use:
const char* GetEnv( const char* tag, const char* def=nullptr ) noexcept {
const char* ret = std::getenv(tag);
return ret ? ret : def;
}
int main() {
int ret=0;
if( GetEnv("DEBUG_LOG") ) {
// Setup debug-logging
} else {
...
}
return (-1==ret?errno:0);
}
The difference between this and the other answers may seem small, but I find such small details are very rewarding when you form habits in how you code.
Just like the fact that getenv() returns a non-const pointer, which could easily lead to bad habits!
I have a function that performs a few string comparisons based on an argument. The strings that are being compared against are not used elsewhere. My instinct is to declare all of the strings as consts at the beginning of the function. However, they could just be inline, or declared on the class level. What is preferred?
Here is the gist of the function:
void MyType::parse(const wstring& input)
{
if (input == value1) { do1; }
else if (input == value2) { do2; }
}
Possible options for the values:
A. Inline values:
if (input == L"foo") { do1; }
B. Function-level values:
void MyType::parse(const wstring& input)
{
const wstring foo = L"foo";
if (input == foo) { do1; }
...
}
C. Class-level static constants:
.h
class MyType
{
private:
static const std::wstring kFoo;
}
.cpp
const wstring MyType::kFoo(L"foo");
...
void MyType::parse(const wstring& input)
{
if (input == kFoo) { do1; }
...
}
There are probably other options as well. Now, opinions differ as to readability, so while those are important, it's impossible to have a definite answer about that. So, when I ask, "which is preferred?" I'm asking about which performs best and has the lowest complexity.
My personal preference:
Keep the literal as close to the point of use as possible - so options A or B, but not C.
To choose between A an B, ask yourself "Does the literal itself make sense to someone else reading this code?". If it does, go for A and the code is still self-documenting. If it doesn't, option B gives you the opportunity to provide a meaningful name to the literal.
Examples:
// option A
void MyType::parse(const wstring& input)
{
if (input == L"QUIT") { quit(); }
else if (input == L"CONTINUE") { read_next(); }
}
// option B
void MyType::parse(const wstring& input)
{
static const wstring quit_command = L"*34!";
static const wstring continue_command = L"*17!";
if (input == quit_command) { quit(); }
else if (input == continue_command) { read_next(); }
}
What do you prefer?
They're not all equivalent of course.
If you give them (named) namespace or global scope, they can get external visibility, meaning you can define them in a separate TU and even change their definition without recompiling (just linking). If that TU is in a dynamic library that linking might be at runtime.
Also, function locals are usually not separately documented. However if these values have significant meaning, you might want to document them. If you don't wish to imply external linkage, make them file-static, e.g.:
namespace /*local to TU*/ {
/** #brief the file pattern is used when ...
*/
constexpr char const* file_pattern = "......";
}
That way, your class declaration doesn't leak implementation details and doesn't need to change if those details change.
So, it's up to you. But consider your needs for testing, maintainability and documentation.
The question you have to ask is: do you see this string being changed/modified in the future? If so, inline will not work. If you know this string will never be changed, received through a get() function, or modified, then I would say inline is best since you do not have to declare space in memory to hold the variable (and save a line of code).
I personally would go with the last variant. You have one single point of change if you require your "Magic String" to be modified, which is always a good idea. Even if you only use the string once, I would suggest that you still have one constant somewhere, otherwise you will do it the one way for this scenario, but the other way in another, which is inconsistent.
Just my 2 ct.
Generally, you should refer to your employer's coding standard.
If that does not explain which to use, ask your team lead.
If he/she does not care, your instincts are fine.
My experience has been varied ... I prefer the const std::string defined close to the first time used.
Edit: (some now missing comment apparently thought the above was incomplete)
Should single-use values be
inline function-level const variables,
class-level static const variables
As I previously stated;
I prefer the single-use value as close to the first time use as possible.
and thus not in the class-level constants (neither static nor otherwise)
I generally prefer them on their own line, so perhaps this means not in-line, and not anonymous. I suppose this is related to the idea of "no magic numbers in your code." (even though this is not a number.)
I have some code that looks like this:
static std::string Foo(const std::string& blah)
{
if ( someWierdEdgeCase() ){
return false; // <-- this line has a compiler error
}
std::string resourcePath;
resourcePath.append("/assets/");
return resourcePath;
}
It used to compile fine, but then I upgraded to Xcode 5.1, and now it no longer compiles. The error I get is the following one:
No viable conversion from 'bool' to 'std::string'
I would like to know what I should replace 'return false' with so that this works the way it used to.
Normally, I would be happy to return something other than false, and clearly that is not good behavior. But somehow this code used to compile and run, and I want to understand what it was doing, in case some other part of this codebase is relying on what is certainly weird behavior.
This:
return false; // <-- this line has a compiler error
There is no standard way to convert bool to std::string (please correct me if there is or was something special in gcc (the old XCode mac compiler)). This means that your code base used to contain explicit code to convert the bool to string.
If it is not compiling now this suggests this conversion was removed from your code base.
A couple of people of suggested alternatives. But I doubt any of these are going to work. As the old code had a depedency on how it used to work. So making any specific recomendation will depend on working out how the old code compiled and what it returned when someWierdEdgeCase() is true. Basically you need to replicate this behavior.
Otherwise you need to hunt down all used cases in your code and change the behavior to match the new behavior. In this case I would change the name of the function. Re-Compile and see where the code breaks and check the behavior at each location and make sure it behaves the same.
static std::string Foo(const std::string& blah)
{
std::string resourcePath = "";
if ( someWierdEdgeCase() ){
return resourcePath; // <-- Now you're returning a string
}
resourcePath.append("/assets/");
return resourcePath;
}
If you need the return type to be - for whatever reason - not always present, return by pointer, instead of returning by value.
static yourType* Foo(const std::string& blah){
if ( someWierdEdgeCase() ){
return 0;
}
}
Then you can test and assign the function in the same line
yourType* result;
if(result = Foo("something")){
// the result was correct
Of course - since your function returns a std::string, you can return an empty string (""), or - also independent of the return type - throw an exception.
I had same issue that with the fact that my interface file and implementation file were using different data types in method declaration.Putting same data type on both place in method declaration error went away.
I'm creating a DLL lib that should be used during runtime (i.e. loaded in Windows 7 with LoadLibrary, closed with FreeLibrary and function handles given by GetProcAddress). This is being done in C++ using Borland C++ Builder. All functions in the DLL should receive some value by reference as parameter (normally std::string).
By now the method I'm using to do this is the following (example) (summarized):
typedef void (*HIS_validity)(string &);
//LoadLibrary
HIS_validity fValidity = (HIS_validity) GetProcAddress(frMain->HIS_DLL.hisLibrary,"checkForValidity");
if (fValidity == NULL) return;
string testeValidade;
fValidity(testeValidade);
const AnsiString testeValidade2(testeValidade.c_str());
if (testeValidade2 != "...")
//etc...
In the DLL:
extern "C" void LIBRARY_API checkForValidity(string &str);
void checkForValidity(string &str)
{
str = "...";
}
Now this code is running fine. The problem is that in some functions I want to pass a whole array of strings by reference. Previously I discovered how to pass a string array by reference here and I though it would be just a matter of ajusting things accordingly:
typedef void (*HIS_patientData)(string (&)[32]);
HIS_patientData fPatientData = (HIS_patientData) GetProcAddress(frMain->HIS_DLL.hisLibrary,"patientDataFields");
string strDado2[32];
fPatientData(strDado2);
frMain->pluginData.patientData.numProntuario = AnsiString(strDado2[cont1++].c_str());
frMain->pluginData.patientData.pacNome = AnsiString(strDado2[cont1++].c_str());
In the DLL:
extern "C" void LIBRARY_API patientDataFields(string (&str)[32]);
void patientDataFields(string (&str)[32])
{
str[0] = "One";
str[1] = "Two";
str[2] = "Three";
//....
}
But here the problem appears. When I compile and run my application, the same problem always come up: if my function in the DLL has only two data attributed to 'str[]', the code goes one after 'fPatientData(strDado2);' but when I read the content of strDado2[0], it has the value of str[1] and strDado2[1] has NULL inside! By the other hand, if I add three or more attributions to 'str[]' in my DLL function, the software always crash when it comes to 'fPatientData(strDado2);' with a pop-up telling "access violation ... in module libstdc++-6.dll".
And I have no ideia what the problem is :T
Thanks for any help,
Momergil
Ok, it seems I found the answer to all such problems... Namely, I'm trying to return a C++ class (std::string) in a "extern "C"" function. It was just a matter of making it return a standart const char* that everything started to run just fine.
Thanks for the contributors,
Momergil
I am working in C++ with two large pieces of code, one done in "C style" and one in "C++ style".
The C-type code has functions that return const char* and the C++ code has in numerous places things like
const char* somecstylefunction();
...
std::string imacppstring = somecstylefunction();
where it is constructing the string from a const char* returned by the C style code.
This worked until the C style code changed and started returning NULL pointers sometimes. This of course causes seg faults.
There is a lot of code around and so I would like to most parsimonious way fix to this problem. The expected behavior is that imacppstring would be the empty string in this case. Is there a nice, slick solution to this?
Update
The const char* returned by these functions are always pointers to static strings. They were used mostly to pass informative messages (destined for logging most likely) about any unexpected behavior in the function. It was decided that having these return NULL on "nothing to report" was nice, because then you could use the return value as a conditional, i.e.
if (somecstylefunction()) do_something;
whereas before the functions returned the static string "";
Whether this was a good idea, I'm not going to touch this code and it's not up to me anyway.
What I wanted to avoid was tracking down every string initialization to add a wrapper function.
Probably the best thing to do is to fix the C library functions to their pre-breaking change behavior. but maybe you don't have control over that library.
The second thing to consider is to change all the instances where you're depending on the C lib functions returning an empty string to use a wrapper function that'll 'fix up' the NULL pointers:
const char* nullToEmpty( char const* s)
{
return (s ? s : "");
}
So now
std::string imacppstring = somecstylefunction();
might look like:
std::string imacppstring( nullToEmpty( somecstylefunction());
If that's unacceptable (it might be a lot of busy work, but it should be a one-time mechanical change), you could implement a 'parallel' library that has the same names as the C lib you're currently using, with those functions simply calling the original C lib functions and fixing the NULL pointers as appropriate. You'd need to play some tricky games with headers, the linker, and/or C++ namespaces to get this to work, and this has a huge potential for causing confusion down the road, so I'd think hard before going down that road.
But something like the following might get you started:
// .h file for a C++ wrapper for the C Lib
namespace clib_fixer {
const char* somecstylefunction();
}
// .cpp file for a C++ wrapper for the C Lib
namespace clib_fixer {
const char* somecstylefunction() {
const char* p = ::somecstylefunction();
return (p ? p : "");
}
}
Now you just have to add that header to the .cpp files that are currently calling calling the C lib functions (and probably remove the header for the C lib) and add a
using namespace clib_fixer;
to the .cpp file using those functions.
That might not be too bad. Maybe.
Well, without changing every place where a C++ std::string is initialized directly from a C function call (to add the null-pointer check), the only solution would be to prohibit your C functions from returning null pointers.
In GCC compiler, you can use a compiler extension "Conditionals with Omitted Operands" to create a wrapper macro for your C function
#define somecstylefunction() (somecstylefunction() ? : "")
but in general case I would advise against that.
I suppose you could just add a wrapper function which tests for NULL, and returns an empty std::string. But more importantly, why are your C functions now returning NULL? What does a NULL pointer indicate? If it indicates a serious error, you might want your wrapper function to throw an exception.
Or to be safe, you could just check for NULL, handle the NULL case, and only then construct an std::string.
const char* s = somecstylefunction();
if (!s) explode();
std::string str(s);
For a portable solution:
(a) define your own string type. The biggest part is a search and replace over the entire project - that can be simple if it's always std::string, or big one-time pain. (I'd make the sole requriement that it's Liskov-substitutable for a std::string, but also constructs an empty string from an null char *.
The easiest implementation is inheriting publicly from std::string. Even though that's frowned upon (for understandable reasons), it would be ok in this case, and also help with 3rd party libraries expecting a std::string, as well as debug tools. Alternatively, aggegate and forward - yuck.
(b) #define std::string to be your own string type. Risky, not recommended. I wouldn't do it unless I knew the codebases involved very well and saves you tons of work (and I'd add some disclaimers to protect the remains of my reputation ;))
(c) I've worked around a few such cases by re-#define'ing the offensive type to some utility class only for the purpose of the include (so the #define is much more limited in scope). However, I have no idea how to do that for a char *.
(d) Write an import wrapper. If the C library headers have a rather regular layout, and/or you know someone who has some experience parsing C++ code, you might be able to generate a "wrapper header".
(e) ask the library owner to make the "Null string" value configurable at least at compile time. (An acceptable request since switching to 0 can break compatibility as well in other scenarios) You might even offer to submit the change yourself if that's less work for you!
You could wrap all your calls to C-stlye functions in something like this...
std::string makeCppString(const char* cStr)
{
return cStr ? std::string(cStr) : std::string("");
}
Then wherever you have:
std::string imacppstring = somecstylefunction();
replace it with:
std::string imacppstring = makeCppString( somecystylefunction() );
Of course, this assumes that constructing an empty string is acceptable behavior when your function returns NULL.
I don't generally advocate subclassing standard containers, but in this case it might work.
class mystring : public std::string
{
// ... appropriate constructors are an exercise left to the reader
mystring & operator=(const char * right)
{
if (right == NULL)
{
clear();
}
else
{
std::string::operator=(right); // I think this works, didn't check it...
}
return *this;
}
};
Something like this should fix your problem.
const char *cString;
std::string imacppstring;
cString = somecstylefunction();
if (cString == NULL) {
imacppstring = "";
} else {
imacppstring = cString;
}
If you want, you could stick the error checking logic in its own function. You'd have to put this code block in fewer places, then.