Most people when declaring strings in C++, or most other languages, do it like so:
std::string example = "example";
However I've seen some code samples where it is done like this:
std::string example("example");
To me it seems like it needlessly obfuscates the code, particularly if there is a using std::string statement hiding somewhere above the declaration in the code making it look like
string example("example");
To some who may be new to the codebase or are coming from other languages it almost looks like it could be a method or a function.
Is there any practical or performance based reason for using the constructor instead of the assignment operator or does it come down to just personal preference?
The practical reason for the second form is that it reflects what actually happens. Your two examples actually - despite their syntactic differences - do exactly the same thing.
They are both calling a constructor which accepts a const char * to initialise example with the literal "example".
The main difference is the way they are interpreted at times. I've lost count of the number of times I've seen people insist that
std::string example = "example";
does an assignment that calls std::strings operator=() function - except that it doesn't.
People who get tired of fielding such claims (and prefer that someone looking at the code can understand what it actually does, wherever possible) therefore sometimes prefer the second form;
std::string example("example");
Sometimes you don't have a choice. Many constructors are explicit (even some of std::string's constructors) and you can't call it with the type object = value syntax, and for consistency type object(value) would be much better. Being explicit prevents mistakes on things like std::vector<char> v = 'c'; or MyString s = 'v'; that doesn't work as one expects
But C++11 introduced the new {} initializer syntax and most modern coding conventions strongly prefer it, so you should use this instead
std::string example{ "example" }; // good
auto example{ "example"s }; // better
Even ISO CPP's Core C++ Guidelines suggests that in ES.23: Prefer the {} initializer syntax
This has the advantage of preventing narrowing, and it works even for in-class initialization
struct foo {
// OK
std::string example1 = { "example" };
std::string example2{ "example" };
std::string example3 = "example";
// Doesn't work
std::string example4("example");
};
To some who may be new to the codebase or are coming from other languages it almost looks like it could be a method or a function.
That's the well-known most vexing parse issue in C++. Both std::string example(std::string(someIdentifier)) and string example(string(someIdentifier)) can represent either a function declaration or a variable definition with initialization. If you learn C++ you have to learn the syntax
In fact most vexing parse is one of the reasons of the introduction to the new {} initialization form
See also
What are the advantages of list initialization (using curly braces)?
Why uniform initialization (initialization with braces) is recommended?
When to use the brace-enclosed initializer?
Related
I realized that in C++ you can initialize any structure with default values. I don't think that was possible under C. Is that correct?
Are there situations in which it still makes sense not to use such a default initialization? Or is it better in any case since it is safer?
I also saw that there are different ways to do this.
Is One Method Better Than Another? Or is it just a matter of taste?
struct STR_Foo {
int value{ 0 };
};
struct STR_Foo {
int value = 0;
};
struct STR_Foo {
int value = { 0 };
};
I realized that in C++ you can initialize any structure with default values. I don't think that was possible under C. Is that correct?
Yes.
Are there situations in which it still makes sense not to use such a default initialization?
If you target Older standard than C++11 - or cross-compatibility with C. Default member initialisers weren't in the language before that - and aren't in C.
If you target C++11 standard and you want the class to be an aggregate. Since C++14 default member initialisers don't disqualify a class from being an aggregate.
If you need an instance of the class to be initialised later and have measured that you cannot afford the very low overhead of redundant initialisation.
I also saw that there are different ways to do this. Is One Method Better Than Another? Or is it just a matter of taste?
The choice to use = or not is stylistic when using curly brackets. Attempting to initialise without = and parentheses instead of curlies ends up being a function declaration for some cases, so you need to disambiguate by using = or curlies.
Curly brackets affect the form of initialisation in some cases. In cases where curlies and no curlies invoke the same constructor, using curlies is recommended because that syntax don't allow narrowing conversions. When curlies invoke a different constructor than no curlies, use the form that does what you need.
These apply to all initialisation; not just default members.
If I have a class:
class className{
int i;
public:
className(int value);
};
What is considered as the best practise for initializing the class variable 'i' from the constructor as per the below choices?
1) Use the actual field name with an underscore:
className::className(int i_){
i = i_;
}
2) Use the actual field name with "this":
className::className(int i){
this->i = i;
}
3) Completely inconsistent things like:
className::className(int value){
i = value;
}
I have seen this question being directly addressed for Java but not so much for C++. I ask because I would favor number 2 as I would personally prefer less variable names being made. However I would like to know what further considerations this could mean for the compiler or linker etc. I would also like to stick with the C++ norm.
Many Thanks!
Yes that's ok.
Some people actually think it idiomatic.
However, your samples all lack the use of initializer lists :)
class className{
int i;
public:
className(int value) : i(value) {};
};
I suggest to avoid the confusion with duplicate names. It makes the compiler complain if you accidentally mess up.
The best practice is to initialize your member variables in the initializer list:
className::className(int i_) : i(i_){}
^^^^^
Reasons:
Performance: You avoid unnecessary calls to members' default constructors.
Having Members not default constructible: If you have member variables that aren't default constructible (i.e., they don't have a default constructor), you are obliged to initialize them in the initializer list.
Having Members const-qualified: Same as 2.
Having Members references to objects: Same as 2.
Readability: Opinion based.
Extensibility: Opinion based.
As far as it concerns the naming issue: IMHO, it's primarily opinion based. Personally, for parameters of a constructor I use the suffix underscore as well.
I am in agreement with #sehe, to clarify on his context of initializer lists:
className::className(int i_) : i(i_) {}
However! I think the identifier names are backwards in terms of appropriateness. i_ should be the private member variable, and i should be the constructor parameter.
My notes on each "choice":
1) It's easy to see which parameters correspond with one another here
2) It's explicitness here
3) I think you've already concluded your opinion on this one by wording it 'Completely Inconsistent' :).
I originally programmed an assignment using Microsoft/visual c++ compilers, but my course requires me to run and compile on unix using G++
However, strncpy_s does not compile using g++, any workaround for my specific program?
This is code snippet that uses it:
void PhoneNumber::setName(const char name[])
{
strncpy_s(_name, name, MAX_NAME_LENGTH);
}
The *_s functions are Microsoft's attempt at being clever and "securing" the C runtime library's string functions. The functions even made it into C99's Appendix K. They are not implemented in Linux' glibc at the time of this writing. If you absolutely must (and I advise against it), just use the normal C library functions correctly (this means no magic numbers and proper buffer sizes everywhere), and yes, this is a pain in the bum.
This might or might not be usable within the context of your assignment, but it is really the only correct answer:
class PhoneNumber
{
private:
std::string name;
// ...
public:
void setName(std::string name);
//...
};
void PhoneNumber::setName(std::string name)
{
this->name = std::move(name); // 'this->' is optional, but clarifies without resorting to some clever renaming of the variables
}
Alternatively, drop the setter altogether:
struct PhoneNumber
{
std::string name;
// ...
};
and assign the member directly. But this style of coding, although perfectly sane, might get you yelled at by your teacher.
Don't use C char arrays in C++. You'll shoot yourself in the foot for no good reason. It also gets rid of the magic number in your code, which is always a plus.
Tiny C++11 and later template wankery. The ideal solution of implementing the setter is using templates, so that a potential costly double-move can be prevented if the setter is called like setName(std::move(some_string)):
template<typename T>
void setName(T&& name) { this->name = std::forward<T>(name); }
This will allow anything that is assignable/moveable to a std::string to be accepted, which is actually quite nice all in all. As an added benefit, you get the best possible code path selected for you automagically. Of course for your assignment this will be huge overkill, but if you take the time to learn about these concepts you might just teach the teacher something. Again, prefer a public member to this template ... wankery, because that is what this is.
You should not be using strncpy or its _s version, it may be quite surprising in its behaviour.
Use strlcpy instead, see strlcpy and strlcat - consistent, safe, string copy and concatenation.
As C++11 introduces the new uniform initialization syntax, many recommend to use it instead the old style syntax.
At least, if it weren't for this so-called corner case:
struct Foo {
Foo(int){
std::cout << "default" << std::endl;
}
Foo(std::initializer_list<int>){
std::cout << "initlist" << std::endl;
}
};
int main(){
Foo f{200}; //prints "initlist"
}
Using a {}-always-style screams for trouble, especially in templates. There seem to be only three safe usages for the new syntax:
explicitly requesting std::initializer_list-constructors
POD-constructors
default-constructors
But there's also a case in which we have to use uniform initialization syntax: non-static data member initializers.
For some reason, C++ can recognize
void Bar() {
Foo f(200);
}
but can't deal with
struct Bar {
Foo f(200);
};
Question #1: Why does the ()-syntax work inside a function but not a class? Does anyone know the rationale behind this?
Putting it all together, lastly we arrive at this silly case:
struct FooBar {
std::vector<int> bar(50); //doesn't work
std::vector<int> bar{50}; //not the intended effect
std::vector<int> bar = std::vector<int>(50); //works
};
Of course, you also can't use auto for data members.
So I either have to awkwardly mix all syntaxes or not use these features at all.
Question #2: Did I misunderstand something? This can't be intended behavior, can it?
Question #1: Why does the ()-syntax work inside a function but not a class? Does anyone know the rationale behind this?
Because it can look like a function declaration, and there already is enough confusion regarding that:
Foo f(); // function declaration. This still catches people out
But you can use (), just using the copy-initialization syntax:
T t = T(args);
Question #2: Did I misunderstand something? This can't be intended behavior, can it?
It is the design behaviour. It is unfortunate that it doesn't play very well with standard library containers of certain types (like std::vector<int> in your example). You just have to remember that an implicit initializer_list constructor trumps all other compatible constructors. You should strive to design your own classes such that they don't suffer from this problem.
See this related question: When to use a brace-enclosed initializer?
It's not allowed because it would lead to more instances of the "most vexing parse" which is already annoying. This isn't a major handicap because you can still use initialization syntax in the constructor body, or use the copy-initialization form.
If you bear in mind that the semantics of a brace-enclosed list is and has always been to provide a list of values to store in the object, then it's clear that std::vector<int> bar{50} should (and does) create a vector containing one int.
Is this code ambiguous or is it perfectly fine (approved by standards/has consistent behavior for any compilers in existence)?
struct SCustomData {
int nCode;
int nSum;
int nIndex;
SCustomData(int nCode, int nSum, int nIndex)
: nCode(nCode)
, nSum(nSum)
, nIndex(nIndex)
{}
};
edit:
yes, I am referring to the fact that the member variables have the same name with formal parameters of the constructor.
No, in this case there are no ambiguity, but consider following:
struct SCustomData {
//...
void SetCode(int nCode)
{
//OOPS!!! Here we do nothing!
//nCode = nCode;
//This works but still error prone
this->nCode = nCode;
}
};
You should draw attention to one of existing coding styles. For instance General Naming Rule in Google C++ Coding Styles or read excellent book "C++ Coding Standards: 101 Rules, Guidelines, and Best Practices" by Herb Sutter and Andrei Alexandrescu.
Your example is unambiguous (to me), but it's not good practise, because it can quickly become as ambiguous as hell.
It's a long while since I've written any C++ in anger, so I'm guessing what the following will do.
Do you KNOW what it will do? Are you sure?
class Noddy
{
int* i;
Noddy(int *i)
: i(i)
{
if(i == NULL)
i = new int;
}
};
If you're referring to using the same name for members and constructor arguments, then that's absolutely fine. However, you might find some people who insist that it's bad practice for some reason.
If you need to access the members in the constructor body, then you need to be careful - either give the arguments different names, or use this-> to access members.
If you're referring to using pseudoHungarian warts to remind people that integers are integers, then that is technically allowed, but has absolutely no benefits and makes the code much harder to read. Please don't do it.
In general, I've prefixed instance variables with underscores and named parameters in the constructor without any prefixes. At the very least, this will disambiguate your parameters from your instance variables. It also makes life less hectic if initializing within the body of the constructor.
struct SCustomData {
int _nCode;
int _nSum;
int _nIndex;
SCustomData(int nCode, int nSum, int nIndex)
: _nCode(nCode), _nSum(nSum), _nIndex(nIndex)
{}
};
// Alternatively
struct SCustomData {
int _nCode;
SCustomData(int nCode)
{
this->_nCode = nCode;
}
};
I don't like stacking the variables the way it was written in the question. I like to save vertical space, and it's also easier for me to read left-to-right. (This is a personal preference of mine, not a mandatory rule or anything like that.)
I would say that this is perfectly fine.
It is my preferred style for constructors that use the initialization list and don't have any code. I think that it reduces confusion because it is obvious which constructor parameter goes to which member.
It is perfectly standard compliant, but there are compilers out there that would not accept member variables having the same name as constructor parameters. In fact, I had to change my open source library for that reason. See this patch