R. Clayton (rclayton@monmouth.edu)
Thu, 15 Jun 2000 14:15:34 -0400 (EDT)
Why doesn't this code compile?
$ cat t0.cc
#include <vector>
#include <iostream>
class readmbox {
public:
vector<vector<char> > table(5, vector<char>(80));
};
int main(void) {
readmbox m;
cout << "m.table.size() = " << m.table.size() << ".\n";
for (unsigned i = 0; i < m.table.size(); i++)
cout << "m.table[" <<i<< "].size() = " << m.table[i].size() << ".\n";
return 0;
}
$ g++ -ansi -pedantic -Wall t0.cc
t0.cc:8: warning: ANSI C++ forbids initialization of member `table'
[ other error messages deleted ]
$
The intention seems clear enough: define table to be a vector of five values,
where each value is a vector of 80 character values. So why doesn't it
compile?
The code doesn't compile because it's confusing a major conceptual distinction
made by C++: the difference between a class and an instance of a class. The
problem is, the variable table does not exist at the time the class readmbox is
being defined.
Remember, table is a member variable for an instance of class readmbox, it is
not a member variable of class readmbox itself. When you're defining a class,
you are not creating an instance of that class, and the instance member
variables don't exist. Because the instance member variables don't exist, you
can't initialize them, and your c++ compiler should complain when you try.
The problem occurs because the code is trying to initialize the non-existent
instance member variable table. What's the solution? The solution seems
pretty clear: wait until table exists, then initialize it. One way to do this
is in a constructor for readmbox:
$ cat t1.cc
#include <vector>
#include <iostream>
class readmbox {
public:
readmbox() {
for (int i = 0; i < 5; i++)
table.push_back(vector<char>(80));
}
vector<vector<char> > table;
};
int main(void) {
readmbox m;
cout << "m.table.size() = " << m.table.size() << ".\n";
for (unsigned i = 0; i < m.table.size(); i++)
cout << "m.table[" <<i<< "].size() = " << m.table[i].size() << ".\n";
return 0;
}
$ g++ -o t1 -ansi -pedantic -Wall t1.cc
$ ./t1
m.table.size() = 5.
m.table[0].size() = 80.
m.table[1].size() = 80.
m.table[2].size() = 80.
m.table[3].size() = 80.
m.table[4].size() = 80.
$
This code works because the constructor creates an instance of class readmbox;
because the instance exists, so does the instance member variable table, and it
can be initialized.
Looking at t1.cc, what readmbox() is essentially doing is implementing
number-and-value initialization for vectors. This seems a clumsy and
inefficient approach to take, particularly because number-and-value
initialization has already been provided as part of the vector class. Is there
some way to avoid duplicated work by initializing table with the already
defined number-and-class initializer for vectors?
It turns out there is, using the colon initializers in constructors. I won't
go into details, but just present an example:
$ cat t4.cc
#include <vector>
#include <iostream>
class readmbox {
public:
readmbox() : table(5, vector<char>(80)) {
}
vector<vector<char> > table;
};
int main(void) {
readmbox m1;
cout << "m1.table.size() = " << m1.table.size() << ".\n";
for (unsigned i = 0; i < m1.table.size(); i++)
cout << "m1.table["<<i<<"].size() = " << m1.table[i].size() << ".\n";
return 0;
}
$ g++ -o t4 -ansi -pedantic -Wall t4.cc
$ ./t4
m1.table.size() = 5.
m1.table[0].size() = 80.
m1.table[1].size() = 80.
m1.table[2].size() = 80.
m1.table[3].size() = 80.
m1.table[4].size() = 80.
$
Now the readmbox() constructor does no work itself; all the work takes place in
the vector's number-and-value constructor.
This archive was generated by hypermail 2.0b3 on Fri Aug 11 2000 - 15:25:05 EDT