When and why should you use String&, String and Const? - c++

I was working on a piece of code.
struct Argument
{
Argument(): s_name(""), name(""), optional(true) {}
Argument(String& s_name_inp, String& name_inp, bool optional_inp):s_name(s_name_inp),name(name_inp),optional(optional_inp){}
.....More code.....
}
Somewhere later in the code:
void addArgument(String& name_inp,bool optional=true)
{
String name;
//Creating a tmep string to store the corrected name if the user doesn't enter - or -- wrt. name of their argument.
name = isDashed(name_inp) ? name_inp : addDash(name_inp) ;
//using the dashed name to check if it's shortname or long name.
if(name.size()>3)
{
//This is the long name.
Argument arg("", name, optional);
insertArgument(arg);
}
else
{
//This is for the short name
Argument arg(name, "", optional);
insertArgument(arg);
}
}
Both Struct Argument and fn addArgument are part of a class where struct Argument is defined in the private and addArgument in the public.
It throws up an error when I run the code..
For Long name one-
error: no instance of constructor "ArgumentParser::Argument::Argument" matches the argument list
argument types are: (const char [1], ArgumentParser::String, __nv_bool)
For Short Name one -
error: no instance of constructor "ArgumentParser::Argument::Argument" matches the argument list
argument types are: (ArgumentParser::String, const char [1], __nv_bool)
I could figure out how to fix it. This error is coming because of the empty strings "" which I enter. Adding const in the struct Argument constructor fixes the problem.
struct Argument
{
Argument(): s_name(""), name(""), optional(true) {}
Argument(const String& s_name_inp, const String& name_inp, bool optional_inp):s_name(s_name_inp),name(name_inp),optional(optional_inp){}
.....More code.....
}
Similarly, declaring a String blank = "" ; and passing it while initializing an obj of struct Argument instead of "" curbs the problem as well. Also, passing String instead of String& in the Argument constructor also solves the issue-
Argument(String s_name_inp, String name_inp, bool optional_inp):s_name(s_name_inp),name(name_inp),optional(optional_inp){}
Thus what I concluded from this is that simply passing "" is a problem since it is not stored in some variable. It doesn't have some location which can be referenced(String&) in case a change is made inside the code. That's why adding a const before String& in the constructor ensures the compiler that no change will be made even though we are passing by ref, so the compiler allows the use of "".
However I do not understand why the compiler is being so 'smart' even though I haven't done any incorrect operation. It's like the compiler is popping bugs for 'security' also, apart from the usual 'errors' we make.
With this question, I also want to understand in a broader sense, the use of const.
I get that it's just for ensuring that no change will be made to the variable being passed(or returned) to a function/constructor. But why do we need it if I, as the programmer, can ensure that I won't be changing the variable. Why do we need const then?
One thing I know is, it can be used to tell others to keep a parameter unchanged if they see your code.(https://www.youtube.com/watch?v=4fJBrditnJU is a good source for learning about const) Also, what is the difference between use of const in these two cases -
int somefunc const(int& var)
{
// var=4; This isn't allowed due to the const in fn
return var;
}
int somefunc(const int& var)
{
// var =4 ; This is also not allowed.
return var;
}
Also, I want to know how passing by reference and passing by value differ if they are just being used for assignments, i.e, no change is being made to them but they are being used for checking conditions, or doing some assignments to other vars.
Adding const String& is like a surety that whatever the user is passing is not being tampered with, in the code, so can't we simply replace it with String? Because passing by value will instantiate a copy of the passed variable/parameter? Why do we use const String& then?
Another question about passing pointers and passing by reference: The only use I know of String&(or int& or any other) is to directly pass the actual 'thing' into the function, not a copy of it, so whatever we do with that 'thing' will be reflected on the original, just like we use pointers to get the changes to be made to the actual 'thing' and not a copy of it. Why don't we use pointers instead of passing by reference? What advantage does it bring?
I know this question is kind of vast but these are all interconnected questions. Answer to one compliments another. Thanks to anyone who takes the time to answer whatever they seems suitable!

Pointers and l-value references are exchangeable, for the most part. It's just less to write at the site of invocation.
The difference between const & and & comes, as you noticed, from a simple reference requiring a variable to reference. A reference with & has the semantic of "let me write that down for you". A const & allows the creation of the temporary copy on-the-fly, and has the semantic of "let me have a look". Pass by value has the meaning of "give me a copy, I decide what to do with it".
In practical experience, avoiding copies is your primary concern. So call-by-value is something you want to avoid for anything bigger than an integral value.
Const-correctness is mostly just design of the C++ language, it's not strictly required from a technical point of view. You can consider it to be a way of saying "trust me, I'm not going to break it".
About passing temporary values to a simple & parameter, think about it for a moment who actually owns the temporary, and for how long it's going to exist. Anything written to it, if you would be allowed to do so, would be lost.
Also think about default parameters, e.g. void foo(const bar &foobar = bar(42)). These are never allowed to be non-const references, as it would result in undefined behavior. That default object may live in a static scope (rather than every caller creating it anew), and someone messing with it would result in changing defaults. Good luck ever finding the cause for that bug.
Even for non-default parameters, const & allows the creation of the temporary at compile time (constexpr constructors), and also folding multiple instances of identical temporaries into a single instance in memory. This optimization would likewise not be possible without the guarantees made by const.
There is a plethora of other cases where const-correctness is also the key to enable compiler optimizations. So it's generally better to use correctly, even if you assumed that your code discipline would had prevented at least undefined behavior.

But why do we need it if I, as the programmer, can ensure that I won't be changing the variable. Why do we need const then?
You could also ensure to not make any errors in coding, so why compiler errors/warnings, unit tests, issue trackers, …
Why would you use the keyword const if you already know variable should be constant?
Use const wherever possible in C++?
Adding const String& is like a surety that whatever the user is passing is not being tampered with, in the code, so can't we simply replace it with String? Because passing by value will instantiate a copy of the passed variable/parameter? Why do we use const String& then?
A class could be more expensive to copy then the indirections over the reference are. Especially if the compiler would be able to inline the function in case of a const & for which no indirection would happen at all.
A copy could introduce unwanted side effects (could be problematic in an environment with limited resources)
A class could have a deleted copy constructor so no copy would be possible at all, but you still want to ensure const correctness.
The only use I know of String&(or int& or any other) is to directly pass the actual 'thing' into the function, not a copy of it, so whatever we do with that 'thing' will be reflected on the original, just like we use pointers to get the changes to be made to the actual 'thing' and not a copy of it. Why don't we use pointers instead of passing by reference? What advantage does it bring?
A pointer can accept a nullptr so you need to handle the case where nullptr is passed (if no nullptr must be passed gsl::not_null could be used). But using pointers would not allow passing temporaries.

Related

Why using const for arguments passed by value? [duplicate]

This question already has answers here:
Const correctness for value parameters
(6 answers)
Closed 9 years ago.
Say you have:
int f( const T a ) { ... }
int g( const T &a ) { ... }
I understand the use of const in g: we don't know how a is used outside the function, so we want to protect it from being modified. However I don't understand the use of const in f, where a is a local copy. Why do we need to protect it from being modified?
I can think of a few reasons:
1) When someone reads the code and see const T a, they know that a should not be modified in the body of the function.
2) The compiler will tell you when you try to modify a in the body of the function. Therefore, adding const can prevent mistakes.
BTW chris already mentioned this in the comments.
3) However, there is another difference in C++11. A constant object cannot be moved from, as a move operation modifies the object. Therefore, you can only make a copy of a in the function body and cannot move from it.
4) Also, if this is a class type, you cannot call non-const members functions on a const object.
Declaring variables const is a good practice.
WHY?
For arguments passed by value to functions, it doesn't matter for the caller whether you declare it const or not. The rationale here is to protect yourself from mistakes while coding, using the compiler to warn you that you are changing the value of a variable, so that you can explicitly confirm this behavior by removing the const modifier. This applies not only to function parameters, but also to local variables.
Based on this rationale, I personaly always start out by declaring all variables const and let the compiler to issue errors when I modify them. Then I check if this behavior is intended and remove the const modifier if it is indeed needed. For better legibility I also always prefer to code in a way my variables are all const.
"I personally tend to not use const except for reference and pointer parameters. For copied objects it doesn't really matter"
If you are using const in function argument there may be one of the following reason.
1-it help the compiler to optimize things a bit.
2-no body can modified argument value in future(if many people working on same code base)

Making a char function parameter const?

Consider this function declaration:
int IndexOf(const char *, char);
where char * is a string and char the character to find within the string (returns -1 if the char is not found, otherwise its position). Does it make sense to make the char also const? I always try to use const on pointer parameters but when something is called by value, I normally leave the const away.
What are your thoughts?
Assuming you don't intend to adjust the value of either parameter:
I would have the function definition as:
int IndexOf( const char * const , const char )
{
//...
}
But keep the function declaration as:
int IndexOf( const char * , char );
In other words:
I'd reveal the bare minimum level of const in the header, but then use the maximum possible level of const in the implimentation.
Why?
Seperating the header and implimentation allows me to change the parameters that are const in the implimentation without ever touching the header (except those that are vitally const, which should require a header change).
It's makes the code more self-documenting.
It makes it harder to introduce bugs without the compiler catching them as errors.
It makes it harder for other programmers to introduce bugs when making future changes.
Making a pass-by-value paramter const or not has "no effect" in terms of affecting the caller of the function - which is why you should keep them out the header - but they can make your implimentation more robust and easier to maintain.
Obviously, if it's more useful to change the parameter rather than copying it into another local variable then don't make it const for the sake of doing so.
Contrary to my co-answerers, I'd make the char const. After all, you don't want to change the character you're looking for in mid-search, do you? And since doing so inadvertently has a good chance of messing up your algorithm, const helps to make your code robust and easy to maintain.
It doesn't make sense because the caller won't be affected if you modify the second parameter's value.
Further, if you need to modify this argument inside the function it may help you save a few bytes on the stack rather than having to declare a separate local variable.
The below code is a good example of modifying an argument instead of having a local variable:
void foo (int count) {
while (count--) {
do_something();
}
}
However, if your function is longer and you don't intend to modify its arguments, it may be rewarding in terms of maintenance to mark the corresponding arguments as const, but only in its definition, not in the declaration that resides in a header file. If you later decide that an argument shouldn't be const, you only have to change it in the definition.
For the example you gave the answers make sense, but in the more general case of passing by value there can be some instances where const might be helpful.
Generally this might be for non POD types where potentially even passing by value doesn't guarantee no visible side effects from changes. Furthermore if you absolutely know that your implementation won't be wanting to change it marking it const can help the compiler find bugs if/when someone accidentally changes the value later.
I tend to live by the rule "mark it const unless there's a reason for it to not be const"
I don't think it is necessary, as the char's value will be copied and any change to it won't be reflected outside of its scope.
It doesn't matter, so long as you are consistent.
As you can see, this question is a religious one. People come down on either side, and tend to fervently disagree with the opposing side.
Arguments can be made for or against either side. The arguments that are made can be contradicted.
For example, the arguments in the "make it const" camp tend to argue that it makes the code more self-documenting for maintenance programmers working on that function. This may well be true, and you might decide this is a good enough reason to mark your by-value parameters as const. The other side of this coin however is that you may decide one day that you do need to modify the variable in the function, which would require that you change the signature, or make a local copy. In addition, which marking is as const does add some documentation for the maintenance programmer, it also adds documentation for the client programmer -- but this documentation is misleading at best. It implies certain semantics to the caller that do not exist.
But whatever you do, you need to be consitant. Either make all your by-value parameters const, or none of them. Inconsitancy will destroy any of the documentary benefits you gain by taking either side.
If it's a 3 line function, the const doesn't help much.
But if you have to understand and maintain a 300 line function, it can be a very important clue that a local variable or parameter will not be changed before line 289, where it is used.
Pro const:
prevents the argument from being accidentally modified within the callee
Contra const:
adds clutter without providing useful information to the caller
implementation changes (ie removing the qualifier) will change the interface
The ideal solution would be to provide the const only in the declaration which is part of the function definition. However, the C standard does not allow this; it will work as expected in all reasonable implementations of the C language, though.
I'd say const would add absolutely nothing to your code.

What is wrong with my syntax in this 1 line bit of code (pointers and references and dereferences oh my)?

The code that I am having trouble with is this line:
result.addElement(&(*(setArray[i]) + *(rhs.setArray[j])));
The + operator in my class is overloaded like this (there are a variety of overloads that can fit in this set, but they all have a similar header):
const Rational Rational::operator+(const Rational &rhs) const
The setarrays in the code above are both arrays of pointers, but the + operator requires references, which might be the problem.
AddElement, the method of result, has this header:
bool Set::addElement(Multinumber* newElement)
The Multinumber* in the header is the parent class of Rational, mentioned above. I don't think any of the specific code matters. I'm pretty sure that it is a syntax issue.
My compiler error is:
68: error: invalid conversion from 'const Multinumber*' to 'Multinumber*'
Thank you for your help!
the issue is with const
bool Set::addElement(Multinumber* newElement) should be Set::addElement(const Multinumber* newElement)
Your operator + returns a const object. However, addElement requires a non-const object, which is where your compiler error is coming from. Basically, addElement is telling you that it feels at liberty to modify your Multinumber at will, but the operator + is beginning you not to modify the returned value.
You should just return a non-const object, unless there's a good reason not to. You're not returning a reference after all.
Of course, if the data in your Set is supposed to be constant and will never be changed, you may as well make addElement take a const pointer, and make sure that it internally deals with const pointers EVERYWHERE.
The issue is with the addElement expecting a non-const where as operator+ is returning a const object.
The fix for the code is cast the return as mentioned below
addElement((Multinumber * )&( *(setArray[i]) + *(rhs.setArray[j])));
If you dont want to cast, as casting might defeat the purpose of type checking here, then you have to change the signature of the addElement. That depending upon your project scope may have impact else where and if this API is public and other developers are using it. Changing signature will impact them also.
So choose wisely.
This code has much more serious issues than you can fix by adding a const or a typecast somewhere.
The result of this code will ultimately be a crash somewhere down the line, because you're passing a pointer to a temporary. Once you finish with line of code that calls addElement, the pointer will be left dangling, and trying to use the object it points to will either result in nonsense (if you're reading the object) or stack corrpution (if you're writing to the object).
The best way to redefine your code would be to change this to
bool Set::addElement(Multinumber newElement) //pass the Multinumber by value
and call addElement as follows:
result.addElement(*setArray[i] + *rhs.setArray[j]);
Note that I eliminated all of the extra parentheses because * has lower precedence than [], so the parentheses around setArray[i] and setArray[i] were redundant. I think the code is more readable this way.
Well really, if I can guess what's going on here, setArray is the internal storage of the Set class, so it's type will need to be redefined from Multinumber** to Multinumber*, in which case the call really should be
result.addElement(setArray[i] + rhs.setArray[j]);
EDIT Ugggh. None of the above will actually allow you to keep your polymorphism. You need to call new Rational somewhere, and the only reasonable place that I can think of is:
result.addElement( new Rational(*setArray[i] + *rhs.setArray[j]) );
This will work without having to redefine Set::addElement.
A better solution would be to redesign the whole thing so that it doesn't depend on polymorphism for numeric classes (because numeric classes really shouldn't be wrapped in pointers in most normal use).

Char array pointer vs string refrence in params

I often see the following structure, especially in constructors:
class::class(const string &filename)
{
}
class::class(const char * const filename)
{
}
By step-by-step debug, I found out the 2nd constructor is always called if I pass a hard-coded string.
Any idea:
1) Why the dual structure is used?
2) What is the speed difference?
Thanks.
Two constructors are needed because you can pass a NULL to your MyClass::MyClass(const std::string &arg). Providing second constructor saves you from a silly crash.
For example, you write constructor for your class, and make it take a const std::string & so that you don't have to check any pointers to be valid if you'd be using const char*.
And everywhere in your code you're just using std::strings. At some point you (or another programmer) pass there a const char*. Here comes nice part of std::string - it has a constructor, which takes char*, and that's very good, apart from the fact, that std::string a_string(NULL) compiles without any problems, just doesn't work.
That's where a second constructor like you've shown comes handy:
MyClass::MyClass(const char* arg)
: m_string(arg ? arg : "")
{}
and it will make a valid std::string object if you pass it a NULL.
In this case I don't think you'd need to worry about any speed. You could try measuring, although I'm afraid you'd be surprised with how little difference (if any) there would be.
EDIT: Just tried std::string a_string(NULL);, compiles just fine, and here's what happens when it is run on my machine (OS X + gcc 4.2.1) (I do recall I tried it on Windows some time ago, result was very similar if not exactly same):
std::logic_error: basic_string::_S_construct NULL not valid
This is useful if the implementation deals with const char*s by itself, but is mostly called by std::string users. These can call using the std::string API, which usually just calls c_str() and dispatches to the const char* implementation. On the other side, if the caller does already have a c-string, no temporary or unneeded std::string needs to be constructed (which can be costly, for longer strings it's a heap allocation).
Also, I once used it to resolve the following case:
My interface took std::string's, but had to be implemented in an external module, thus the STL binary versions of both the module AND the caller module had to match exactly, or it would have crashed (not really good for a portable library… ). So I changed the actual interface to use const char*, and added std::string overloads which I declared inline, so they weren't exported. It didn't break existing code, but resolved all my module boundary problems.
1) Why the dual structure is used?
The string reference version is required if std::string objects are to be used conveniently as parametersm as there is no implicit conversion from a std::string to a const char const. The const char * const version is optional, as character arrays can implicitly be converted into std::strings, but it is more efficient, as no temporary std::string need be created.
2) What is the speed difference?
You will need to measure that yourself.
They are offered basically for convenience. Some times, if you call C functions, you get char* pointers. Others, you get strings, so offering both constructors is just a convenience for the caller. As for the speed, both have virtually the same speed, as they both send a memory address to the constructor.

(Obj) C++: Instantiate (reference to) class from template, access its members?

I'm trying to fix something in some Objective C++ (?!) code. I don't know either of those languages, or any of the relevant APIs or the codebase, so I'm getting stymied left and right.
Say I have:
Vector<char, sizeof 'a'>& sourceData();
sourceData->append('f');
When i try to compile that, I get:
error: request for member 'append' in 'WebCore::sourceData', which is of non-class type 'WTF::Vector<char, 1ul >& ()();
In this case, Vector is WTF::Vector (from WebKit or KDE or something), not STD::Vector. append() very much is supposed to be a member of class generated from this template, as seen in this documentation. It's a Vector. It takes the type the template is templated on.
Now, because I never write programs in Real Man's programming languages, I'm hella confused about the notations for references and pointers and dereferences and where we need them.
I ultimately want a Vector reference, because I want to pass it to another function with the signature:
void foobar(const Vector<char>& in, Vector<char>& out)
I'm guessing the const in the foobar() sig is something I can ignore, meaning 'dont worry, this won't be mangled if you pass it in here'.
I've also tried using .append rather than -> because isn't one of the things of C++ references that you can treat them more like they aren't pointers? Either way, its the same error.
I can't quite follow the error message: it makes it sound like sourceData is of type WTF:Vector<char, 1ul>&, which is what I want. It also looks from the those docs of WTF::Vector that when you make a Vector of something, you get an .append(). But I'm not familiar with templates, either, so I can't really tell i I'm reading that right.
EDIT:
(This is a long followup to Pavel Minaev)
WOW THANKS PROBLEM SOLVED!
I was actually just writing an edit to this post that I semi-figured out your first point after coming across a reference on the web that that line tells the compiler your forward declaring a func called sourceData() that takes no params and returns a Vector of chars. so a "non-class type" in this case means a type that is not an instance of a class. I interpreted that as meaning that the type was not a 'klass', i.e. the type of thing you would expect you could call like .addMethod(functionPointer).
Thanks though! Doing what you suggest makes this work I think. Somehow, I'd gotten it into my head (idk from where) that because the func sig was vector&, I needed to declare those as &'s. Like a stack vs. heap pass issue.
Anyway, that was my REAL problem, because I tried what you'd suggested about but that doesn't initialize the reference. You need to explicitly call the constructor, but then when I put anything in the constructor's args to disambiguate from being a forward decl, it failed with some other error about 'temporary's.
So in a sense, I still don't understand what is going on here fully, but I thank you heartily for fixing my problem. if anyone wants to supply some additional elucidation for the benefit of me and future google people, that would be great.
This:
Vector<char, sizeof 'a'>& sourceData();
has declared a global function which takes no arguments and returns a reference to Vector. The name sourceData is therefore of function type. When you try to access a member of that, it rightfully complains that it's not a class/struct/union, and operator-> is simply inapplicable.
To create an object instead, you should omit the parentheses (they are only required when you have any arguments to pass to the constructor, and must be omitted if there are none):
Vector<char, sizeof 'a'> sourceData;
Then you can call append:
sourceData.append('f');
Note that dot is used rather than -> because you have an object, not a pointer to object.
You do not need to do anything special to pass sourceData to a function that wants a Vector&. Just pass the variable - it will be passed by reference automatically:
foobar(sourceData, targetData);
Dipping your toes in C++ is never much fun. In this case, you've run into a couple of classic mistakes. First, you want to create an instance of Vector on the stack. In this case the empty () is interpreted instead as a declaratiton of a function called sourceData that takes no agruments and returns a reference to a Vector. The compiler is complaining that the resulting function is not a class (it's not). To create an instance of Vector instead, declare the instance without the () and remove the &. The parentheses are only required if you are passing arguments to the instance constructor and must be omitted if there are no arguments.
You want
Vector<char, sizeof 'a'> sourceData;
sourceData.append('f');
Vector<char, sizeof 'a'> outData; //if outData is not instantiated already
foobar(sourceData, outData);
This Wikipedia article gives a decent introduction to C++ references.