Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C++ (http://www.velocityreviews.com/forums/f39-c.html)
-   -   would you consider this function const? (http://www.velocityreviews.com/forums/t806938-would-you-consider-this-function-const.html)

john 12-14-2011 03:17 PM

would you consider this function const?
 
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);
}

};

Victor Bazarov 12-14-2011 04:19 PM

Re: would you consider this function const?
 
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

john 12-15-2011 01:10 PM

Re: would you consider this function const?
 
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

Victor Bazarov 12-15-2011 01:21 PM

Re: would you consider this function const?
 
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

john 12-15-2011 01:44 PM

Re: would you consider this function const?
 
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


Victor Bazarov 12-15-2011 02:11 PM

Re: would you consider this function const?
 
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

john 12-15-2011 02:30 PM

Re: would you consider this function const?
 
>>
>> 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




Victor Bazarov 12-15-2011 03:06 PM

Re: would you consider this function const?
 
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

john 12-15-2011 05:42 PM

Re: would you consider this function const?
 
>>> 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.





Victor Bazarov 12-15-2011 06:32 PM

Re: would you consider this function const?
 
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


All times are GMT. The time now is 03:21 PM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.