Ok, I'm really getting helpful answers from this site!!!

Here's my new C++ question:
How much code can go in an initializer list?
Can I call new SomeClass() to get a pointer to initialize something even if it wasn't in the original argment list?
Can I do math on the arguments?
Could I put a for loop inside an initializer list somehow?
Basically I see simple examples all over, but I'm just curious how many options I have in these initializer lists...
Also, I often see underscores or something like that.
Is there any significance to those?
Thanks,
Sean

Recommended Answers

All 3 Replies

Here is a good article on initialization lists.

>>How much code can go in an initializer list?

As much as you can while keeping the code neat. This means, don't go overboard trying to fit everything in the list, make sure it stays understandable and readable. Aside from that, there are do's and don't's. First you need to initialize any member or base class that does not have a default constructor, because anything missing from the list will be constructed with the default constructor and if it is not available (private or absent) the compiler will complain with an error. That includes references (data members that are references to something), they can only be assigned once, on construction, so they need to be set in the initialization list.

Second, you cannot (or should not) refer to the this pointer or use any data member of the class to initialize any of the data members.

Third, you cannot call a virtual method, neither can you do that in the body of the constructor anyways.

From the top of my head that's about it. You can call functions, do math operations, whatever, as long as they are initializing the data members or base classes. You cannot put general expressions like "member1(init_value), some_function_call(), member2(init_value2), .." between the commas.


>>Can I call new SomeClass() to get a pointer to initialize something even if it wasn't in the original argment list?

Yeah sure, why not? You are not restricted to what is in the argument list (which most people would call the constructor's parameters, "arguments" are generally used for class / function template arguments).


>>Can I do math on the arguments?

Yes.


>>Could I put a for loop inside an initializer list somehow?

Well, there is no point in doing general statements in the initialization list, and you will not be allowed to. But, with <algorithm> for example, you could do a for-loop with a for_each() call or any of the other similar algorithmic functions. It's just like calling a function. But you need to make it into a "member(init_value)" expression, where init_value can essentially be as complex as you like as long as it evaluates to a value. But remember, the main purpose of the initialization list is to have clear simple list of initialization of the data members and base classes as well as a gain in performance by being able to construct those members once with the proper initial parameters (because in the body, the data members will wind up being initialized once by default and then set to their initial value). If the expression init_value is too complex, it might just break both of these rules, by making things look to weird and being inefficient or just the same as before.


>>Basically I see simple examples all over, but I'm just curious how many options I have in these initializer lists...

Again, the reason why you see mostly simple examples of initialization lists is that there is usually no point in having anything too complex in there.


>>Also, I often see underscores or something like that.
Is there any significance to those?

No, there is no significance, this is simply a "style" for many programmers to use underscores as either the data members or the parameters. It's just a way to differentiate data members, local variables, and function parameters, some use leading underscore, no underscore, and trailing underscore for these three, respectively. Some use other styles (like me!), but that's quite common to see, so it's good to know.

>>Could I put a for loop inside an initializer list somehow
Just to add a little more,

Yea king of, you can do something like this :

struct Foo{
 int i;
 Foo() : i( bar() );
};

and inside the bar function, there could be a loop or whatever a regular function could have.

>>Also, I often see underscores or something like that

It is just preference, but note that any variable starting with 2 underscores are reserved, and any variable starting with 1 underscore followed by a capital letter are reserved.

Well I am going to try to give you part of the answer, others (more knowledgeable) will hopefully fill the details in. I am going to assume you are talking about class initializers.

So let us do this via examples, so consider:

class A 
{
  const int vInt;          // Must be initialized in constructors
  double V;                // Can be initialized in constructors
  const complexClass cX;   // Will be initialized in constructors
  otherClass* Lptr;          // Can be initialized in constructors

  public:

    A();

    static double calcValue(const int);
    double getLen() const;
};

In this example there are four variables and two are constant. There are a set of rules about what happens in each case. First of all, all the variables can be initialized in the constructor. e.g.

A::A() : vInt(5),V(3.4),cX(1,2,3),Lptr(new otherClass(4.5,"filename")
{}

As you can see all variables are initialized. Now please not that the order matters.
You can only access them in order. This will not provide the correct results:

A::A() : vInt(40),Lptr(new otherClass(4.5,"filename"),V(Lptr->getLen())
{}

Note that despite the order on the constructor definition, the order is as given in the class definition, i.e. the value of Lptr is set after V has been set. In this code the likely effect is a memory violation/core dump of some sort. (You do get compiler warnings on all modern compilers)

Also note that I have not initialized cX. That is ok if and only if, cX has a default contructor, that takes no values. If cX's constructor only took three ints then that would be a compile error.

Now coming back to how to initialize complex values, consider this:

A::A() : vInt(3),V( vInt*sin(1.0+vInt)/cosh(4.5) ),Lptr(0)
{}

As you can see V is being initialized with a functional form, e.g. using the sin and cosh functions (from cmath) and putting the value in the variable.

You might be tempted do complex things with a self-written function e.g

// This works:
A::A() : vInt(3),V( calcValue(vInt) ),Lptr(0)
{}
// This won't:
A::A() : vInt(3),V( getLen() ),Lptr(0)
{}

the reason the last will not work is because the implied variable this does not exist until after the initializers have been finished. However, that does mean that this example works:

A::A() : vInt(3),Lptr(0)
{
  V=getLen();
}

So in short you can initialize variables from extremely complex functions, if you so wish.

Your final point was about the used of _ . This is commonly attached to private variables in a class and to variables in a function. I really don't think it helps. Mainly because when the variable is encountered, say in the A.cxx file for the class A, it is no different in effect to a global variable, and the usage is same. However, the initial _ slows down the "forward reading effect". (You don't read this post, word by work, but effectively scan ahead). The other problem is overcomes is name pollution, but that is dealt with much better using namespaces. (and not make them all global again with using namespace std; etc.)

However, many people disagree and I think the much more important thing is to be very consistent in how you name variables, either use what the existing project uses, or if starting from scratch, pick something and stay with it.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.