I'm facing some uncertainty with const template arguments.
Maybe someone could explain the general strategy.
#include <vector>
int main(int arc, char** argv)
{
std::vector<const int> vec;
const int i = 5;
vec.push_back(i);
vec[0] = 4; //const has gone away
std::vector<const int*> pvec;
const int* pi = new int(5);
pvec.push_back(pi);
*(pvec[0]) = 4; // not possible because const, compile error
return 0;
}
From the first impression, it is not possible to create a vector of
const ints.
But you can do it with pointers.
When you take whatever you put into the vector, you get a copy of it.
That means that your copy is not const, no matter what you put in.
The pointers you put in are not const - the ints they point to are. A
const pointer to a changeable int looks like
int * const x;
> When you take whatever you put into the vector, you get a copy of it.
> That means that your copy is not const, no matter what you put in.
>
#include <vector>
template<class T> class MyInt {
T var;
public:
MyInt(T i):var(i){}
T GetT() {return var;}
T& GetTRef() {return var;}
MyInt& operator=(const MyInt& t) {
if (this != &t)
{
var = t.GetT();
}
return *this;
}
};
int main(int arc, char** argv)
{
const int i = 5;
MyInt<const int> mi(i);
//mi.GetTRef() = 4; // error, variable is const
int x = 5;
MyInt<int> mx(x);
mx.GetTRef() = 4; // this works
return 0;
}
Is that really a justification? In that example you can instantiate
MyInt with "const int" and only "int". In both cases the value is
copied, but var is not "int" in both cases.
One of the requirements for elements in a container like
std::vector<>, is that those elements be assigneable and copyable. So
const int is a no-no but const int* is fine since that pointer can be
reseated.
Do I remember wrongly that the next standard will introduce the means
to actually allow standard containers to have const elements (in other
words, you can add and remove elements from the container, but you can't
modify the values of existing ones)?
This is exactly the reason I always use const on the right (correct)
side, especially when dealing with pointers/references.
'const int' is simply a special case way to write: 'int const'. or
with pointers 'const int *' is 'int const *'
Remember: declarations are read right to left from the variable name.
With this in mind the problem is extremely clear:
int const * - poiter to a constant int (pointer can change, integer
cannot)
int * const - constant pointer to an int (integer can change, pointer
cannot)
That seems dangerous. To remove an element would imply destruction,
which is non-const. You can still get const-only access to elements
via const_iterator or const&, or std::set essentially functions like
this.
> I'm facing some uncertainty with const template arguments.
> Maybe someone could explain the general strategy.
> #include <vector>
> int main(int arc, char** argv)
> {
> std::vector<const int> vec;
This is illegal---undefined behavior according to the standard.
It doesn't compile with my compiler (g++, with the usual
options). And whatever happens if it does compile, you can't
count on it.
> const int i = 5;
> vec.push_back(i);
> vec[0] = 4; //const has gone away
Maybe. Or maybe it core dumps. Or maybe just about anything
else. (I would generally expect it not to compile, but the
standard doesn't require an error message.
> std::vector<const int*> pvec;
> const int* pi = new int(5);
> pvec.push_back(pi);
> *(pvec[0]) = 4; // not possible because const, compile error
> return 0;
> }
> From the first impression, it is not possible to create a
> vector of const ints. But you can do it with pointers.
What's in the vector cannot be const. You can create a vector
of non-const pointers to const (which is what you did), but not
of const pointers to anything. (You're probably being confused
by a widespread abuse of language. int const* is not a const
pointer, but a pointer to const. A const pointer would be int*
const or int const* const. More generally, just remember that
the const applies to whatever precedes it.)
--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
I guess my initial post was somewhat missleading.
I only wanted to say that, when you want to have a vector of const
objects, you have to use pointers!
The "assignable & copyable" rule is the point.
"const T" would be copyable, but not assignable.
I thought it should be possible to allow the creation of a vector of
"const T" because at creation there is no need for an assignment. Or
am I missing something?
Incorrect.
void deleteFoo(const Foo* const foo)
{
delete foo; // Compiles and works just fine.
}
> You can still get const-only access to elements
> via const_iterator or const&, or std::set essentially functions like
> this.
Even if you *can* get const access with the current system, that
doesn't mean it wouldn't be nice if there was a way to *ensure* that the
values of the elements are never modified by accident.
Perhaps more to the point, if it's coupled with move semantics (you
referred to the "next standard") removal doesn't imply destruction: the
element just gets moved somewhere else. Similarly, move insertion would
just move an already-created object into the container.
--
Richard Herring
[...]
> I thought it should be possible to allow the creation of a
> vector of "const T" because at creation there is no need for
> an assignment. Or am I missing something?
Yes. That assignment is needed for functions like insert. In
fact, push_back is defined, and often implemented, in terms of
insert, and on seeing insert, the compiler can't know that you
never in fact insert except at the end. So it has to
instantiate the code for both cases, and that code contains
assignments.
> xdotx wrote:
> > That seems dangerous. To remove an element would imply destruction,
> > which is non-const.
>
> Incorrect.
>
> void deleteFoo(const Foo* const foo)
> {
> delete foo; // Compiles and works just fine.
> }
Or even just
void destroys_const()
{
const Foo foo;
}