Passing a string to a function in C++(object vs string) - c++

What is the difference between the following two in C++?
fun(L"text1")
VS
std::wstring var = "text1"
fun(var)
In the first case, it is being passed as an object while the second case passes it as a wstring.
How should fun() be defined to handle both?
EDIT:
I have two function definitions
fun(void*)
fun(std::wstring)
std::wstring t = "bla";
fun(t);
fun(L"msg");
When fun(t) is called it goes to the definition of fun(std::wstring)
But when fun(L"msg") is called it goes to fun(Void*). Instead I want it to goto fun(std::wstring)

The first is passed as a wide-string literal. In the second case, you pass by value (and hence copy) or by reference an std::wstring object.
To handle both, you have to define two overloads of your function:
void fun(const wchar_t* s);
void fun(const std::wstring& s);
or you can just define the wstring version, because the literal will implicitly convert to a wstring.

To handle both you should define the fun method as:
void fun(const std::wstring& str);
then in both cases you would be passing a const reference to a wstring because the compiler is allowed to implicitly cast one type to another if the type being cast to has a constructor that takes one argument of the type being cast from unless that constructor is marked as explicit.
Example:
class wstring
{
public:
// constructor not marked as explicit and takes one argument of type whar_t*
wstring(const wchar_t* str);
};
wstring myString = L"hello world"; // implicit cast from wchar_t* to wstring
The only difference between the two examples you've given is that in the first you are passing an rvalue (which you can only bind to a const reference) and in the second you are passing an lvalue (which you can bind to both const and non-const reference).

In given examples there is no much difference, because compiler will generate constant data containing your literal and use it in both cases.
In the first case, raw literal will be used from string table of your module. This is as fast as possible code without heap allocation (actually no allocations).
In the second case, compiler will allocate string buffer in the heap, which results into malloc() call and strcpy(). This will increase time of your code and cause more memory fragmentation.
You should use std string classes only when you really need to use their useful methods, otherwise, TCHAR buffers are just excellent choice.

Related

Function call parameter, char * vs string default constructor

While calling a function/method in C++11 and above, which one is better (if any difference)?
Lets assume this function/method:
void func(std::string s) { ... }
Which one is best between the following?
func(std::string())
or
func("")
And more generally, is there any advantage to always call the constructor explicitly during initialization or parameter passing?
It's better to call the default constructor, because it's guaranteed to not do any unnecessary work.
When passing an empty string literal, it could be that the string implementation does some work processing that string (compute its length for example). An empty string literal isn't a magic bullet that can be treated differently from non-empty string literals. It's type is const char[1], which decays into const char*, and that's it - the std::string constructor dealing with this literal will end up doing more work than necessary.
From cppreference for std::string::string():
Default constructor. Constructs empty string (zero size and unspecified capacity). If no allocator is supplied, allocator is obtained from a default-constructed instance.
... and for std::string::string(const char*):
Constructs the string with the contents initialized with a copy of the null-terminated character string pointed to by s. The length of the string is determined by the first null character. [...]
For further reading, see also this short article.
I would like to compare func(std::string()) with func(""):
func(std::string())
You create an std::string object with default parameter is empty string
Then pass std::string object to func function. You pass it by value, and a new std::string object will be allocated in stack memory, and call a copy constructor to initialized it.
In this case, there are two std::string object is allocated.
func("")
You pass an empty string, so compiler will allocate a std::string object in stack memory, and use std::string(const char*) constructor.
In this case, there is only 1 std::string object allocated.
So, I think for this specific case, func("") maybe better.

Is it good practice to pass `char []` to a function which accepts `std::string&`

I am not facing any issues with below code but is it good practice to pass char [] to a function which accepts std::string& as a parameter
const char* function(std::string& MyString)
{
MyString = "Hello World";
return MyString.c_str();
}
int main()
{
char MyString[50];
/*
*Is it good practice to cast like this?
*what possible issues i could face because of this casting?
*/
function((std::string)MyString);
std::cin.get();
return 0;
}
This simply won't work because it will require creation of temporary std::string which can not be bound to l-value reference. Even if function took a reference to std::string const creation of temporary would have an impact of performance. So depending on nature of the function it may be a good idea to add an overload that accepts a pointer to a c-string as well. Alternatively, if function is not going to modify the string you can make it accept std::string_view so it can handle both std::string and c-strings.
No, it is bad practice, as the cast has no effect; a std::string can be constructed from a char * with a non-explicit constructor, so you can remove the cast and you'll get exactly the same code (just with an implicit construction instead of an explicit cast).
Now as written, you'll get an error (at least with a non-broken compiler), as you can't pass a temporary object to a non-const lvalue reference. But if you change the function to take a const std::string &, it will work just fine.
Also bad practice is returning the char * you get by calling std::string::c_str() -- this pointer will only be valid as long as the string object is not modified or destroyed -- so the returned pointer will become invalid (dangling) as soon a the temp you passed as an argument was destroyed. If you were to save that returned pointer in a local variable in main and then try to do something with it (like printing it), that would be undefined behavior.
In short passing char[] to function accepting string is common practice (from C). And it is not bad. The explicit cast is not good here. The function also is not good, as it not accept passing char[] ...

How you convert a std::string_view to a const char*?

Compiling with gcc-7.1 with the flag -std=c++17, the following program raises an error:
#include <string_view>
void foo(const char* cstr) {}
void bar(std::string_view str){
foo(str);
}
The error message is
In function 'void bar(std::string_view)':
error: cannot convert 'std::string_view {aka std::basic_string_view<char>}' to 'const char*' for argument '1' to 'void foo(const char*)'
foo(str);
I'm surprised there is no conversion to const char* because other libraries (abseil, bde), provide similar string_view classes which implicitly convert to const char*.
A std::string_view doesn't provide a conversion to a const char* because it doesn't store a null-terminated string. It stores a pointer to the first element, and the length of the string, basically. That means that you cannot pass it to a function expecting a null-terminated string, like foo (how else are you going to get the size?) that expects a const char*, and so it was decided that it wasn't worth it.
If you know for sure that you have a null-terminated string in your view, you can use std::string_view::data.
If you're not you should reconsider whether using a std::string_view in the first place is a good idea, since if you want a guaranteed null-terminated string std::string is what you want. For a one-liner you can use std::string(object).data() (note: the return value points to a temporary std::string instance that will get destroyed after the end of the expression!).
Simply do a std::string(string_view_object).c_str() to get a guaranteed null-terminated temporary copy (and clean it up at the end of the line).
This is required because string view doesn't guarantee null termination. You can have a view into the middle of a longer buffer, for example.
If this use case is expensive and you have proven it to be a bottleneck, you can write an augmented string_view that tracks if it is null terminated (basically, if it was constructed from a raw char const*).
Then you can write a helper type that takes this augmented string_view and either copies it to a std::string or stores the augmented string_view directly, and has an implicit cast-to-char const* that returns the properly null-terminated buffer.
Then use that augmented helper type everywhere in your code base instead of string_view, possibly augmenting string view interaction with std string as well to catch the cases where you have a view that goes to the end of the std string buffer.
But really, that is probably overkill.
A better approach is probably rewriting the APIs that take const char* to take string_view.
You can call foo(std::string(str).c_str()).
using object.data() solved my problem with compiler error C2664

Is there a way to pass a string literal as reference in C++

Within C++ it is common to pass by reference instead of pointer if a value can not be NULL.
Suppose I have a function with the following signature, which is often used with a string literal.
void setText( const char* text );
I was wondering how I could change the function in such a way that it accepts a reference (and has the advantage not to accept NULL)?
If I would change it to (const char& text) then it would be a ref to a single char. From which the address can ba taken inside the function... but feels not nice.
Another option would be (const std::string& text) which has the disadvantage that it always calls a constructor and does some dynamic memory allocation.
Any other common ways, or just stick to the std::string& or the char* ?
Honestly, I would just keep the const char* text function and add an overload const std::string& text function that calls the first one with setText(text.c_str())
There's a slight problem here in that C++ and references-to-arrays aren't the best pair. For reference, see: C++ pass an array by reference
Since you're talking about binding a reference to a string, and a string is an array of characters, we run into that problem head-on. In light of this, the best we can really do is bind a ref to a const char*, which looks like this:
void ref(const char* const& s);
But this doesn't do what you want; this binds a reference to a pointer, and all it guarantees is that the pointer itself exists, not that it's pointing to a valid string literal.
This same problem is present in the std::string& examples: those only guarantee that you've bound to a std::string object, but that string could very well be empty, so you still haven't guaranteed yourself a string that has anything of value in it.
In the end, I'll second what Zan says. const char* is a well respected idiom passing string literals, and then having a second overload that binds to strings is a nice convenience.
(One last note: std::string doesn't "always" allocate memory. Implementations with the small string optimization will skip it for strings as long as 23 characters.)

cstring -> c++ string conversion

If I have a function
void x(std::string const& s)
{
...
}
And I am calling it as x("abc"), will string constructor allocate memory and copy data in it?
The std::string constructor will be called with a const char* argument
There is no telling whether memory would be allocated (dynamically), but the chances are that your standard library implementation has the SSO in place, which means it can store small strings without dynamic allocations.
SSO: Meaning of acronym SSO in the context of std::string
The question is tagged with 'performance', so it's actually a good question IMO.
All compilers I know will allocate a copy of the string on the heap. However, some implementation could make the std::string type intrinsic into the compiler and optimize the heap allocation when an r-value std::string is constructed from a string literal.
E.g., this is not the case here, but MSVC is capable of replacing heap allocations with static objects when they are done as part of dynamic initialization of statics, at least in some circumstances.
Yes, the compiler will generate the necessary code to create a std::string and pass it as argument to the x function.
Constructors which take a single argument, unless marked with the explicit keyword, are used to implicitly convert from the argument type to an instance of the object.
In this example, std::string has a constructor which takes a const char* argument, so the compiler uses this to implicitly convert your string literal into a std::string object. The const reference of that newly created object is then passed to your function.
Here's more information: What does the explicit keyword mean in C++?