Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c++ > #12497 > unrolled thread
| Started by | john <gh14tq5@yahoo.com> |
|---|---|
| First post | 2011-12-14 10:17 -0500 |
| Last post | 2011-12-19 23:48 -0800 |
| Articles | 17 — 6 participants |
Back to article view | Back to comp.lang.c++
would you consider this function const? john <gh14tq5@yahoo.com> - 2011-12-14 10:17 -0500
Re: would you consider this function const? Victor Bazarov <v.bazarov@comcast.invalid> - 2011-12-14 11:19 -0500
Re: would you consider this function const? john <gh14tq5@yahoo.com> - 2011-12-15 08:10 -0500
Re: would you consider this function const? Victor Bazarov <v.bazarov@comcast.invalid> - 2011-12-15 08:21 -0500
Re: would you consider this function const? john <gh14tq5@yahoo.com> - 2011-12-15 08:44 -0500
Re: would you consider this function const? Leigh Johnston <leigh@i42.co.uk> - 2011-12-15 14:07 +0000
Re: would you consider this function const? Leigh Johnston <leigh@i42.co.uk> - 2011-12-15 14:14 +0000
Re: would you consider this function const? Victor Bazarov <v.bazarov@comcast.invalid> - 2011-12-15 09:11 -0500
Re: would you consider this function const? john <gh14tq5@yahoo.com> - 2011-12-15 09:30 -0500
Re: would you consider this function const? Victor Bazarov <v.bazarov@comcast.invalid> - 2011-12-15 10:06 -0500
Re: would you consider this function const? john <gh14tq5@yahoo.com> - 2011-12-15 12:42 -0500
Re: would you consider this function const? Victor Bazarov <v.bazarov@comcast.invalid> - 2011-12-15 13:32 -0500
Re: would you consider this function const? yatremblay@bel1lin202.(none) (Yannick Tremblay) - 2011-12-19 18:16 +0000
Re: would you consider this function const? Tobias Müller <troplin@bluewin.ch> - 2011-12-19 19:05 +0000
Re: would you consider this function const? Joshua Maurice <joshuamaurice@gmail.com> - 2011-12-19 14:36 -0800
Re: would you consider this function const? Tobias Müller <troplin@bluewin.ch> - 2011-12-20 06:28 +0000
Re: would you consider this function const? Joshua Maurice <joshuamaurice@gmail.com> - 2011-12-19 23:48 -0800
| From | john <gh14tq5@yahoo.com> |
|---|---|
| Date | 2011-12-14 10:17 -0500 |
| Subject | would you consider this function const? |
| Message-ID | <jcaem0$gac$1@speranza.aioe.org> |
Are the following functions an abuse of good usage of 'const'? I think
func3 is an abuse, but I'm not sure if func1 or func2, in isolation,
would be considered poor usage since they do not actually modify an
instance of A themselves (although they do leave the door open). Thanks.
class B;
class A
{
B* m_b;
public:
void func1(A* &a) const
{
a = const_cast<A*>(this);
}
B* func2() const { return m_b; }
// because we could do
void func3() const
{
// now we can change m_b;
B* b = func2();
// now we can change this;
A* a;
func1(a);
}
};
[toc] | [next] | [standalone]
| From | Victor Bazarov <v.bazarov@comcast.invalid> |
|---|---|
| Date | 2011-12-14 11:19 -0500 |
| Message-ID | <jcai9t$ee9$1@dont-email.me> |
| In reply to | #12497 |
On 12/14/2011 10:17 AM, john wrote:
> Are the following functions an abuse of good usage of 'const'? I think
> func3 is an abuse, but I'm not sure if func1 or func2, in isolation,
> would be considered poor usage since they do not actually modify an
> instance of A themselves (although they do leave the door open). Thanks.
>
> class B;
>
> class A
> {
>
> B* m_b;
>
> public:
>
> void func1(A* &a) const
> {
> a = const_cast<A*>(this);
> }
>
> B* func2() const { return m_b; }
>
> // because we could do
> void func3() const
> {
> // now we can change m_b;
> B* b = func2();
>
> // now we can change this;
> A* a;
> func1(a);
> }
>
> };
IME 'const_cast' is good only for one thing: to add const where one
needs an overload resolution to go a particular way. Any other use of
'const_cast' is an instance of abuse. That's just IME, of course.
As with 'func2', there is nothing inherently wrong. The pointer is
const, but the object to which the pointer points isn't. If the object
to which m_b points is *owned* by 'this', then I think a slight change
in design might accomplish the intended protection:
const B* func2() const { return m_b; }
B* funct2() { return m_b; }
Otherwise, if m_b does not designate ownership, and hence does not call
for ensuring protection, all is well.
V
--
I do not respond to top-posted replies, please don't ask
[toc] | [prev] | [next] | [standalone]
| From | john <gh14tq5@yahoo.com> |
|---|---|
| Date | 2011-12-15 08:10 -0500 |
| Message-ID | <jccrkj$uec$1@speranza.aioe.org> |
| In reply to | #12502 |
On 12/14/2011 11:19 AM, Victor Bazarov wrote:
> On 12/14/2011 10:17 AM, john wrote:
snipped ....
>
> IME 'const_cast' is good only for one thing: to add const where one
> needs an overload resolution to go a particular way. Any other use of
> 'const_cast' is an instance of abuse. That's just IME, of course.
Could you give an example of the use of const_cast in this case? I do
not quite follow what you are saying.
>
> As with 'func2', there is nothing inherently wrong. The pointer is
> const, but the object to which the pointer points isn't. If the object
> to which m_b points is *owned* by 'this', then I think a slight change
> in design might accomplish the intended protection:
>
> const B* func2() const { return m_b; }
> B* funct2() { return m_b; }
>
> Otherwise, if m_b does not designate ownership, and hence does not call
> for ensuring protection, all is well.
This makes sense. Thanks.
John
[toc] | [prev] | [next] | [standalone]
| From | Victor Bazarov <v.bazarov@comcast.invalid> |
|---|---|
| Date | 2011-12-15 08:21 -0500 |
| Message-ID | <jccs9c$ovg$1@dont-email.me> |
| In reply to | #12536 |
On 12/15/2011 8:10 AM, john wrote:
> On 12/14/2011 11:19 AM, Victor Bazarov wrote:
>> On 12/14/2011 10:17 AM, john wrote:
> snipped ....
>>
>> IME 'const_cast' is good only for one thing: to add const where one
>> needs an overload resolution to go a particular way. Any other use of
>> 'const_cast' is an instance of abuse. That's just IME, of course.
>
> Could you give an example of the use of const_cast in this case? I do
> not quite follow what you are saying.
This is from memory, I don't have a good working example right now...
When you want to call a const member function for a non-const object,
and a non-const member function also exists and overloads the const one,
the non-const would be picked - it's a better match. That's where you
could force the compiler into picking the one you want:
#include <iostream>
#include <ostream>
struct foo {
void bar() const { std::cout << "const bar\n"; }
void bar() { std::cout << "regular bar\n"; }
};
int main() {
// ...
foo f;
f.bar(); // non const is picked.
const_cast<const foo&>(f).bar(); // const version
}
..something like that, anyway. It also happens in the context of a
non-const member that is [partially] implemented in terms of a const
member function, for instance. This is artificial, of course:
struct foo {
void bar() const {
std::cout << "const bar\n"; }
void bar() {
std::cout << "non-";
const_cast<const foo*>(this)->bar(); }
};
HTH
> [..]
V
--
I do not respond to top-posted replies, please don't ask
[toc] | [prev] | [next] | [standalone]
| From | john <gh14tq5@yahoo.com> |
|---|---|
| Date | 2011-12-15 08:44 -0500 |
| Message-ID | <jcctkm$i7j$1@speranza.aioe.org> |
| In reply to | #12537 |
On 12/15/2011 8:21 AM, Victor Bazarov wrote:
> On 12/15/2011 8:10 AM, john wrote:
>> On 12/14/2011 11:19 AM, Victor Bazarov wrote:
>>> On 12/14/2011 10:17 AM, john wrote:
>> snipped ....
>>>
>>> IME 'const_cast' is good only for one thing: to add const where one
>>> needs an overload resolution to go a particular way. Any other use of
>>> 'const_cast' is an instance of abuse. That's just IME, of course.
>>
>> Could you give an example of the use of const_cast in this case? I do
>> not quite follow what you are saying.
>
> This is from memory, I don't have a good working example right now...
> When you want to call a const member function for a non-const object,
> and a non-const member function also exists and overloads the const one,
> the non-const would be picked - it's a better match. That's where you
> could force the compiler into picking the one you want:
>
> #include <iostream>
> #include <ostream>
> struct foo {
> void bar() const { std::cout << "const bar\n"; }
> void bar() { std::cout << "regular bar\n"; }
> };
>
> int main() {
> // ...
> foo f;
> f.bar(); // non const is picked.
> const_cast<const foo&>(f).bar(); // const version
> }
>
> ..something like that, anyway. It also happens in the context of a
> non-const member that is [partially] implemented in terms of a const
> member function, for instance. This is artificial, of course:
>
> struct foo {
> void bar() const {
> std::cout << "const bar\n"; }
> void bar() {
> std::cout << "non-";
> const_cast<const foo*>(this)->bar(); }
> };
>
> HTH
>
>> [..]
>
> V
I see. That makes sense.
One of the issues that spurred this question (related to my func1 in the
original post) is the following. I have a 3D mesh composed of
Volumes/Faces/Edges/Vertices. So, I have a Volume, Face, Edge, and
Vertex class, each derived from a base Topology class. The mesh is
consistent, so given a particular instance of one of the classes, there
are functions that return geometry information such as connectivity. In
particular, each class has a virtual function (declared as pure virtual
at the base Topology class)
virtual void GetVolumes(std::set<Volume*> volumes);
that returns a list of pointers to the volumes associated with the
entity. I want to make this function 'const' since it does not change
the element. For a Face, Edge, and Vertex, this poses no problem.
However, for a volume instance, the function should return a pointer to
just itself, so if GetVolumes is const, then I have
void Volume::GetVolumes(std::set<Volume*> volumes) const
{
volumes.clear();
volumes.insert(const_cast<Volume*>(this));
}
I do not see how to have the GetVolumes function const without the use
of const_cast in the Volume::GetVolumes function. Is there a more
intelligent way to get the same result?
Thanks,
John
[toc] | [prev] | [next] | [standalone]
| From | Leigh Johnston <leigh@i42.co.uk> |
|---|---|
| Date | 2011-12-15 14:07 +0000 |
| Message-ID | <TaKdnQUQiZ6zYnTTnZ2dnUVZ8iadnZ2d@giganews.com> |
| In reply to | #12538 |
On 15/12/2011 13:44, john wrote:
>
> virtual void GetVolumes(std::set<Volume*> volumes);
>
> that returns a list of pointers to the volumes associated with the
> entity. I want to make this function 'const' since it does not change
> the element. For a Face, Edge, and Vertex, this poses no problem.
> However, for a volume instance, the function should return a pointer to
> just itself, so if GetVolumes is const, then I have
>
> void Volume::GetVolumes(std::set<Volume*> volumes) const
> {
> volumes.clear();
> volumes.insert(const_cast<Volume*>(this));
> }
>
> I do not see how to have the GetVolumes function const without the use
> of const_cast in the Volume::GetVolumes function. Is there a more
> intelligent way to get the same result?
>
Try overloading GetVolumes:
virtual void GetVolumes(std::set<Volume*> volumes);
virtual void GetVolumes(std::set<const Volume*> volumes) const;
HTH.
/Leigh
[toc] | [prev] | [next] | [standalone]
| From | Leigh Johnston <leigh@i42.co.uk> |
|---|---|
| Date | 2011-12-15 14:14 +0000 |
| Message-ID | <3vydnVav7-h3nXfTnZ2dnUVZ8ridnZ2d@giganews.com> |
| In reply to | #12539 |
On 15/12/2011 14:07, Leigh Johnston wrote:
> On 15/12/2011 13:44, john wrote:
>>
>> virtual void GetVolumes(std::set<Volume*> volumes);
>>
>> that returns a list of pointers to the volumes associated with the
>> entity. I want to make this function 'const' since it does not change
>> the element. For a Face, Edge, and Vertex, this poses no problem.
>> However, for a volume instance, the function should return a pointer to
>> just itself, so if GetVolumes is const, then I have
>>
>> void Volume::GetVolumes(std::set<Volume*> volumes) const
>> {
>> volumes.clear();
>> volumes.insert(const_cast<Volume*>(this));
>> }
>>
>> I do not see how to have the GetVolumes function const without the use
>> of const_cast in the Volume::GetVolumes function. Is there a more
>> intelligent way to get the same result?
>>
>
> Try overloading GetVolumes:
>
> virtual void GetVolumes(std::set<Volume*> volumes);
> virtual void GetVolumes(std::set<const Volume*> volumes) const;
As Victor pointed out that should be:
virtual void GetVolumes(std::set<Volume*>& volumes);
virtual void GetVolumes(std::set<const Volume*>& volumes) const;
or:
virtual std::set<Volume*> GetVolumes();
virtual std::set<const Volume*> GetVolumes() const;
/Leigh
[toc] | [prev] | [next] | [standalone]
| From | Victor Bazarov <v.bazarov@comcast.invalid> |
|---|---|
| Date | 2011-12-15 09:11 -0500 |
| Message-ID | <jccv7e$8if$1@dont-email.me> |
| In reply to | #12538 |
On 12/15/2011 8:44 AM, john wrote:
> On 12/15/2011 8:21 AM, Victor Bazarov wrote:
>> On 12/15/2011 8:10 AM, john wrote:
>>> On 12/14/2011 11:19 AM, Victor Bazarov wrote:
>>>> On 12/14/2011 10:17 AM, john wrote:
>>> snipped ....
>>>>
>>>> IME 'const_cast' is good only for one thing: to add const where one
>>>> needs an overload resolution to go a particular way. Any other use of
>>>> 'const_cast' is an instance of abuse. That's just IME, of course.
>>>
>>> Could you give an example of the use of const_cast in this case? I do
>>> not quite follow what you are saying.
>>
>> This is from memory, I don't have a good working example right now...
>> When you want to call a const member function for a non-const object,
>> and a non-const member function also exists and overloads the const one,
>> the non-const would be picked - it's a better match. That's where you
>> could force the compiler into picking the one you want:
>>
>> #include <iostream>
>> #include <ostream>
>> struct foo {
>> void bar() const { std::cout << "const bar\n"; }
>> void bar() { std::cout << "regular bar\n"; }
>> };
>>
>> int main() {
>> // ...
>> foo f;
>> f.bar(); // non const is picked.
>> const_cast<const foo&>(f).bar(); // const version
>> }
>>
>> ..something like that, anyway. It also happens in the context of a
>> non-const member that is [partially] implemented in terms of a const
>> member function, for instance. This is artificial, of course:
>>
>> struct foo {
>> void bar() const {
>> std::cout << "const bar\n"; }
>> void bar() {
>> std::cout << "non-";
>> const_cast<const foo*>(this)->bar(); }
>> };
>>
>> HTH
>>
>>> [..]
>>
>> V
>
> I see. That makes sense.
>
> One of the issues that spurred this question (related to my func1 in the
> original post) is the following. I have a 3D mesh composed of
> Volumes/Faces/Edges/Vertices. So, I have a Volume, Face, Edge, and
> Vertex class, each derived from a base Topology class. The mesh is
> consistent, so given a particular instance of one of the classes, there
> are functions that return geometry information such as connectivity. In
> particular, each class has a virtual function (declared as pure virtual
> at the base Topology class)
>
> virtual void GetVolumes(std::set<Volume*> volumes);
That doesn't look right. Did you lose the ampersand before the argument
name?
>
> that returns a list of pointers to the volumes associated with the
> entity. I want to make this function 'const' since it does not change
> the element. For a Face, Edge, and Vertex, this poses no problem.
> However, for a volume instance, the function should return a pointer to
> just itself, so if GetVolumes is const, then I have
>
> void Volume::GetVolumes(std::set<Volume*> volumes) const
> {
> volumes.clear();
> volumes.insert(const_cast<Volume*>(this));
> }
>
> I do not see how to have the GetVolumes function const without the use
> of const_cast in the Volume::GetVolumes function. Is there a more
> intelligent way to get the same result?
What happens if you change the type of the argument to
std::set<const Volume*>
? If it's a set of constant volumes, that's what the type should
express. If you find it difficult to type, use a typedef *or* introduce
some kind of 'Volume proxy' and keep that instead of the pointer to Volume.
V
--
I do not respond to top-posted replies, please don't ask
[toc] | [prev] | [next] | [standalone]
| From | john <gh14tq5@yahoo.com> |
|---|---|
| Date | 2011-12-15 09:30 -0500 |
| Message-ID | <jcd09b$umt$1@speranza.aioe.org> |
| In reply to | #12540 |
>>
>> One of the issues that spurred this question (related to my func1 in the
>> original post) is the following. I have a 3D mesh composed of
>> Volumes/Faces/Edges/Vertices. So, I have a Volume, Face, Edge, and
>> Vertex class, each derived from a base Topology class. The mesh is
>> consistent, so given a particular instance of one of the classes, there
>> are functions that return geometry information such as connectivity. In
>> particular, each class has a virtual function (declared as pure virtual
>> at the base Topology class)
>>
>> virtual void GetVolumes(std::set<Volume*> volumes);
>
> That doesn't look right. Did you lose the ampersand before the argument
> name?
>
Yes, it should be
virtual void GetVolumes(std::set<Volume*>& volumes);
>>
>> that returns a list of pointers to the volumes associated with the
>> entity. I want to make this function 'const' since it does not change
>> the element. For a Face, Edge, and Vertex, this poses no problem.
>> However, for a volume instance, the function should return a pointer to
>> just itself, so if GetVolumes is const, then I have
>>
>> void Volume::GetVolumes(std::set<Volume*> volumes) const
>> {
>> volumes.clear();
>> volumes.insert(const_cast<Volume*>(this));
>> }
>>
>> I do not see how to have the GetVolumes function const without the use
>> of const_cast in the Volume::GetVolumes function. Is there a more
>> intelligent way to get the same result?
>
> What happens if you change the type of the argument to
>
> std::set<const Volume*>
>
> ? If it's a set of constant volumes, that's what the type should
> express. If you find it difficult to type, use a typedef *or* introduce
> some kind of 'Volume proxy' and keep that instead of the pointer to Volume.
I will have to look at whether I can do that or not. My guess is that,
for the most part, I will need non-const Volume*'s. It's a huge code
base, so a change like that could ripple to a lot of places.
John
[toc] | [prev] | [next] | [standalone]
| From | Victor Bazarov <v.bazarov@comcast.invalid> |
|---|---|
| Date | 2011-12-15 10:06 -0500 |
| Message-ID | <jcd2dn$r0e$1@dont-email.me> |
| In reply to | #12542 |
On 12/15/2011 9:30 AM, john wrote:
>>>
>>> One of the issues that spurred this question (related to my func1 in the
>>> original post) is the following. I have a 3D mesh composed of
>>> Volumes/Faces/Edges/Vertices. So, I have a Volume, Face, Edge, and
>>> Vertex class, each derived from a base Topology class. The mesh is
>>> consistent, so given a particular instance of one of the classes, there
>>> are functions that return geometry information such as connectivity. In
>>> particular, each class has a virtual function (declared as pure virtual
>>> at the base Topology class)
>>>
>>> virtual void GetVolumes(std::set<Volume*> volumes);
>>
>> That doesn't look right. Did you lose the ampersand before the argument
>> name?
>>
>
> Yes, it should be
>
> virtual void GetVolumes(std::set<Volume*>& volumes);
>
>
>>>
>>> that returns a list of pointers to the volumes associated with the
>>> entity. I want to make this function 'const' since it does not change
>>> the element. For a Face, Edge, and Vertex, this poses no problem.
>>> However, for a volume instance, the function should return a pointer to
>>> just itself, so if GetVolumes is const, then I have
>>>
>>> void Volume::GetVolumes(std::set<Volume*> volumes) const
>>> {
>>> volumes.clear();
>>> volumes.insert(const_cast<Volume*>(this));
>>> }
>>>
>>> I do not see how to have the GetVolumes function const without the use
>>> of const_cast in the Volume::GetVolumes function. Is there a more
>>> intelligent way to get the same result?
>>
>> What happens if you change the type of the argument to
>>
>> std::set<const Volume*>
>>
>> ? If it's a set of constant volumes, that's what the type should
>> express. If you find it difficult to type, use a typedef *or* introduce
>> some kind of 'Volume proxy' and keep that instead of the pointer to
>> Volume.
>
> I will have to look at whether I can do that or not. My guess is that,
> for the most part, I will need non-const Volume*'s. It's a huge code
> base, so a change like that could ripple to a lot of places.
Well, depending on the domain and the purpose for which the pointers are
collected, it might be OK to const_cast them like that. After all, it
is unlikely that any object of your Volume class is ever created in a
constant memory, so the 'const' here is just a pretense. Keep in mind,
however, that const_cast can be abused. And don't abuse it. If you can
rework your design in such a way that wouldn't call for the use of
'const_cast' to cast *away* any constness, it could lead to a more
robust system, methinks.
I wonder (not that you need to explain, just wonder along with me), how
is Volume and, say, Edge derive from the same class. What is common
about them (aside from 'GetVolumes')? Also, can you have nested
Volumes? You know, an egg inside a duck inside a hare hidden in a
trunk... Seems like if your answer is 'no', then a Volume cannot derive
from Topology since you essentially make Topology aware of a type that
will be derived from it, which is usually a no-no...
V
--
I do not respond to top-posted replies, please don't ask
[toc] | [prev] | [next] | [standalone]
| From | john <gh14tq5@yahoo.com> |
|---|---|
| Date | 2011-12-15 12:42 -0500 |
| Message-ID | <jcdbi9$ren$1@speranza.aioe.org> |
| In reply to | #12544 |
>>> What happens if you change the type of the argument to >>> >>> std::set<const Volume*> >>> >>> ? If it's a set of constant volumes, that's what the type should >>> express. If you find it difficult to type, use a typedef *or* introduce >>> some kind of 'Volume proxy' and keep that instead of the pointer to >>> Volume. >> >> I will have to look at whether I can do that or not. My guess is that, >> for the most part, I will need non-const Volume*'s. It's a huge code >> base, so a change like that could ripple to a lot of places. > > Well, depending on the domain and the purpose for which the pointers are > collected, it might be OK to const_cast them like that. After all, it is > unlikely that any object of your Volume class is ever created in a > constant memory, so the 'const' here is just a pretense. Keep in mind, > however, that const_cast can be abused. And don't abuse it. If you can > rework your design in such a way that wouldn't call for the use of > 'const_cast' to cast *away* any constness, it could lead to a more > robust system, methinks. > > I wonder (not that you need to explain, just wonder along with me), how > is Volume and, say, Edge derive from the same class. What is common > about them (aside from 'GetVolumes')? Also, can you have nested Volumes? > You know, an egg inside a duck inside a hare hidden in a trunk... Seems > like if your answer is 'no', then a Volume cannot derive from Topology > since you essentially make Topology aware of a type that will be derived > from it, which is usually a no-no... Well, a lot of functionality is common to all element types. For example, every Topology (be it a volume, edge, face, vertex) has functions that can return its unique id, its center point, its bounding vertices, its 'type', its dimension. Every Topology stores another class object that can compute geometry on itself, for example position vector, unitary vectors, etc. So there is a lot of common functionality that is declared as pure virtual or virtual at the base class and some common data members. To answer you other question, nested volumes are not allowed. I do not understand you comment that Volume cannot derive from Topology. I do not see a problem with doing it.
[toc] | [prev] | [next] | [standalone]
| From | Victor Bazarov <v.bazarov@comcast.invalid> |
|---|---|
| Date | 2011-12-15 13:32 -0500 |
| Message-ID | <jcdefm$669$1@dont-email.me> |
| In reply to | #12548 |
On 12/15/2011 12:42 PM, john wrote: > [...] I do not > understand you comment that Volume cannot derive from Topology. I do not > see a problem with doing it. Nah... Forget I mentioned it. Do a const_cast. Five years from now expect a maintenance nightmare. If it doesn't materialize, consider yourself lucky. If your program doesn't live that long, all the better. V -- I do not respond to top-posted replies, please don't ask
[toc] | [prev] | [next] | [standalone]
| From | yatremblay@bel1lin202.(none) (Yannick Tremblay) |
|---|---|
| Date | 2011-12-19 18:16 +0000 |
| Message-ID | <jcnv2j$9qa$1@dont-email.me> |
| In reply to | #12502 |
In article <jcai9t$ee9$1@dont-email.me>,
Victor Bazarov <v.bazarov@comcast.invalid> wrote:
>
>IME 'const_cast' is good only for one thing: to add const where one
>needs an overload resolution to go a particular way. Any other use of
>'const_cast' is an instance of abuse. That's just IME, of course.
I would tolerate const_cast inside a method when conceptually, a
method is const (i.e. does not conceptually change the object) but due
to implementation details, the object internal needs to be modified.
I very rarely see a reason to use it. But for example, some peoples
are fans of delaying initialisation using a pattern like:
class A
{
public:
A(): m_initDone(false), ... {};
std::string foo() const
{
if(!m_initDone)
{
const_cast<A *>(this)->init();
}
// do the work
}
private:
void init() {...};
bool m_initDone;
// other member variables
}
I am not a big fan of the above but this would be an example where
const_cast allow an object to modify its internals without breaking
the concept that the object has not changed.
Unfortunately, most of the time const_cast is used to cast-away
constness from code that is const-correct to interface with
const-incorrect code when the correct thing to do would be fix the
const-incorrect code :-( (Actually, most of the time I see it, C-style
hard casts are being used which is even worse).
Yannick
[toc] | [prev] | [next] | [standalone]
| From | Tobias Müller <troplin@bluewin.ch> |
|---|---|
| Date | 2011-12-19 19:05 +0000 |
| Message-ID | <1265628847346013785.792200troplin-bluewin.ch@news.aioe.org> |
| In reply to | #12665 |
none <yatremblay@bel1lin202.> wrote:
> I very rarely see a reason to use it. But for example, some peoples
> are fans of delaying initialisation using a pattern like:
>
> class A
> {
> public:
> A(): m_initDone(false), ... {};
> std::string foo() const
> {
> if(!m_initDone)
> {
> const_cast<A *>(this)->init();
> }
> // do the work
> }
> private:
> void init() {...};
> bool m_initDone;
> // other member variables
> }
>
> I am not a big fan of the above but this would be an example where
> const_cast allow an object to modify its internals without breaking
> the concept that the object has not changed.
IMO it's better to declare the members that are touched by the
initialization as 'mutable'. In most cases, those are only a few large
objects.
This allows you to declare the init() method as const and you don't have to
cast anything.
Tobi
[toc] | [prev] | [next] | [standalone]
| From | Joshua Maurice <joshuamaurice@gmail.com> |
|---|---|
| Date | 2011-12-19 14:36 -0800 |
| Message-ID | <159f510a-aafd-4c29-b74d-bebbe5bba0bf@32g2000yqp.googlegroups.com> |
| In reply to | #12666 |
On Dec 19, 11:05 am, Tobias Müller <trop...@bluewin.ch> wrote:
> none <yatremblay@bel1lin202.> wrote:
> > I very rarely see a reason to use it. But for example, some peoples
> > are fans of delaying initialisation using a pattern like:
>
> > class A
> > {
> > public:
> > A(): m_initDone(false), ... {};
> > std::string foo() const
> > {
> > if(!m_initDone)
> > {
> > const_cast<A *>(this)->init();
> > }
> > // do the work
> > }
> > private:
> > void init() {...};
> > bool m_initDone;
> > // other member variables
> > }
>
> > I am not a big fan of the above but this would be an example where
> > const_cast allow an object to modify its internals without breaking
> > the concept that the object has not changed.
>
> IMO it's better to declare the members that are touched by the
> initialization as 'mutable'. In most cases, those are only a few large
> objects.
> This allows you to declare the init() method as const and you don't have to
> cast anything.
Why would you ever declare an init method as const? An init method
must be the poster child of a method which modifies the object.
Upon 2 seconds of reflection, is this because you're writing code
without exceptions and more or less without constructors? I guess in
that light your comment isn't incredibly silly - a const object still
needs to be initialized, and in that case one isn't using constructors
because one isn't using exceptions, and one has decided to go with the
init method approach as opposed to the zombie object flag.
[toc] | [prev] | [next] | [standalone]
| From | Tobias Müller <troplin@bluewin.ch> |
|---|---|
| Date | 2011-12-20 06:28 +0000 |
| Message-ID | <1398171957346054772.291910troplin-bluewin.ch@news.aioe.org> |
| In reply to | #12669 |
Joshua Maurice <joshuamaurice@gmail.com> wrote: > Why would you ever declare an init method as const? An init method > must be the poster child of a method which modifies the object. > > Upon 2 seconds of reflection, is this because you're writing code > without exceptions and more or less without constructors? I guess in > that light your comment isn't incredibly silly - a const object still > needs to be initialized, and in that case one isn't using constructors > because one isn't using exceptions, and one has decided to go with the > init method approach as opposed to the zombie object flag. If you didn't read the post I was referring to: we're talking about /lazy/ initialization, i.e. initialization on first use. The first use could be a const method and if you don't want to const_cast, init must be const which is only possible if the initialized members are declared mutable. Imagine for example an XML DOM tree that is only parsed on demand, and only those parts that are actually used. Tobi
[toc] | [prev] | [next] | [standalone]
| From | Joshua Maurice <joshuamaurice@gmail.com> |
|---|---|
| Date | 2011-12-19 23:48 -0800 |
| Message-ID | <60939729-ed00-4c6a-b58b-61f24ded8d83@p16g2000yqd.googlegroups.com> |
| In reply to | #12677 |
On Dec 19, 10:28 pm, Tobias Müller <trop...@bluewin.ch> wrote: > Joshua Maurice <joshuamaur...@gmail.com> wrote: > > Why would you ever declare an init method as const? An init method > > must be the poster child of a method which modifies the object. > > > Upon 2 seconds of reflection, is this because you're writing code > > without exceptions and more or less without constructors? I guess in > > that light your comment isn't incredibly silly - a const object still > > needs to be initialized, and in that case one isn't using constructors > > because one isn't using exceptions, and one has decided to go with the > > init method approach as opposed to the zombie object flag. > > If you didn't read the post I was referring to: we're talking about /lazy/ > initialization, i.e. initialization on first use. The first use could be a > const method and if you don't want to const_cast, init must be const which > is only possible if the initialized members are declared mutable. > > Imagine for example an XML DOM tree that is only parsed on demand, and only > those parts that are actually used. I see. My apologies. The init method isn't a public exposed function, but merely a internal implementation detail. (The alternative is of course to const_cast before calling init, and having init be non-const. I don't realy think there's much of a difference between the two approaches, so nevermind.)
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.c++
csiph-web