Friday, September 25, 2015

Digest for comp.lang.c++@googlegroups.com - 13 updates in 3 topics

Kalle Olavi Niemitalo <kon@iki.fi>: Sep 26 01:27AM +0300


> [Quoted text removed due to X-No-Archive]
 
In C, you can write
 
void fn(void)
{
struct same { int same; };
struct same same;
same.same = 0;
}
 
and there is no ambiguity; same means the variable,
struct same means the type, and same.same means the
data member. I suppose C++ tries to be compatible
with C header files that define such structures,
and therefore cannot forbid them outright.
JiiPee <no@notvalid.com>: Sep 25 02:25PM +0100

Say I have a class with some pointer which points to a data if set and
to null if not set:
 
class MyClass
{
void setData(int* data) { m_data = data; }
void useData();
private:
int* m_data{null_ptr};
};
 
Lets say we have to set the value where its pointing to: *m_data.
Now, in useData we have to check whether m_data is null to be able to
use it:
 
void MyClass::useData()
{
if(!m_data)
return;
// m_data is set, so can safely be used
*m_data = 2015;
}
 
Now (and I get this a lot), what is the best practise to secure m_data?
because lets say we have this checking:
if(!m_data)
return;
in 20 different places, there is a possibility I forget to check it and
program crashes. I could created a function:
 
void MyClass::safelySetData(int val)
{
if(!m_data)
return;
*m_data = val;
}
 
but this does not stop other member functions getting access to m_data
and use it with null pointer (crashing).
 
I was thinking creating a new class and putting it to a private member:
 
class Data
{
void setDataPointTo(int* data) { m_data = data; }
void reallySafelySetData(int val) { if(m_data) *m_data = val; }
private:
int* m_data{null_ptr};
};
 
and having Data object in MyClass:
 
class MyClass
{
private:
Data m_data{null_ptr};
};
 
Now this would do the job, but its a bit difficult way to do a simple
single variable thing. Is there any other, more simple, way to secure
m_data so that functions cannot touch it? How do you do this? Or you
just check the null-case and hope that no function is missusing the pointer?
 
Best way would be if I could somehow tell that only safelySetData can
modify m_data pointer. But that is not possible in C++ I think?
Paavo Helde <myfirstname@osa.pri.ee>: Sep 25 09:34AM -0500

> return;
> in 20 different places, there is a possibility I forget to check it
> and program crashes.
 
The best practice is to get rid of the pointer. If the data needs to
remain a separate object by some reason, then one way is to use a
reference instead of the pointer and initialize it in the MyClass
constructor. Reference cannot be null, so problem solved.
 
> private:
> int* m_data{null_ptr};
> };
 
Yes, that's the way to go if there is no way to avoid the pointer. Such
simple wrappers are easily optimized away by the compiler so there is no
difference performance-wise.
JiiPee <no@notvalid.com>: Sep 25 04:26PM +0100

On 25/09/2015 15:34, Paavo Helde wrote:
> JiiPee <no@notvalid.com> wrote in news:YWbNx.1$5b4.0@fx04.am4:
 
> The best practice is to get rid of the pointer.
 
In my situation I cannot bce a thread-function returns a pointer...
 
 
> Yes, that's the way to go if there is no way to avoid the pointer. Such
> simple wrappers are easily optimized away by the compiler so there is no
> difference performance-wise.
 
ok. The question is obviously that do we need to do this wrapper or not?
is it necessary? I kind of like it makes sure nobody can use
null-pointer... but it takes more work, and sometimes lazy.. :)
mark <mark@invalid.invalid>: Sep 25 05:29PM +0200

On 2015-09-25 16:34, Paavo Helde wrote:
> remain a separate object by some reason, then one way is to use a
> reference instead of the pointer and initialize it in the MyClass
> constructor. Reference cannot be null, so problem solved.
 
With C++11, you have reference_wrapper:
http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper
 
This can be quite useful, if you want to use a reference but need to be
able to rebind it. They can also be stuffed into standard containers.
Paavo Helde <myfirstname@osa.pri.ee>: Sep 25 10:47AM -0500

>>> int* m_data{null_ptr};
>>> };
 
>> Yes, that's the way to go if there is no way to avoid the pointer.
Such
>> simple wrappers are easily optimized away by the compiler so there is
no
>> difference performance-wise.
 
> ok. The question is obviously that do we need to do this wrapper or
not?
> is it necessary? I kind of like it makes sure nobody can use
> null-pointer... but it takes more work, and sometimes lazy.. :)
 
You already almost completed it, and changing 20 code locations calling
it is not so hard. I bet writing those 20 tedious checks was more work,
more boring, and more error-prone.
 
Cheers
Paavo
JiiPee <no@notvalid.com>: Sep 25 06:54PM +0100

On 25/09/2015 16:47, Paavo Helde wrote:
> You already almost completed it, and changing 20 code locations calling
> it is not so hard. I bet writing those 20 tedious checks was more work,
> more boring, and more error-prone.
 
yes I kind of agree ...
JiiPee <no@notvalid.com>: Sep 25 06:57PM +0100

On 25/09/2015 16:27, Stefan Ram wrote:
>> Now this would do the job, but its a bit difficult way to do a simple
>> single variable thing.
> I'd do it this way too. It is not difficult.
 
ok, good to know people agree with it. So I can start using it then...
 
I just felt the class for one variable only is a bit too "heavy", but
thats the way to do it.
 
Maybe the language can someday have a security key for this. It might be
a good new feature for C++ :)
Paavo Helde <myfirstname@osa.pri.ee>: Sep 25 01:37PM -0500


> ok, good to know people agree with it. So I can start using it then...
 
> I just felt the class for one variable only is a bit too "heavy", but
> thats the way to do it.
 
There are many useful classes with no data members at all in C++.
 
The general idea is that a single class should have a single
"responsibility". Managing the null-or-not-null data pointer seems a
pretty clear responsibility.

> Maybe the language can someday have a security key for this. It might
be
> a good new feature for C++ :)
 
Your probably mean the standard library, not the C++ core language.
Anyway, it is not so simple because it is not straightforward what should
happen if the pointer is not in the expected state in either of the
get/set part. In my own code I would probably put asserts there, instead
of just ignoring any inconsistencies (as your design appears to
prescribe).
 
Cheers
Paavo
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Sep 25 09:08PM +0200

On 9/25/2015 3:25 PM, JiiPee wrote:
> private:
> int* m_data{null_ptr};
> };
 
This general idea of encapsulation is indeed the way to go, provided
that it's really necessary to store and access values in a location
specified and occasionally changed by client code.
 
 
> pointer?
 
> Best way would be if I could somehow tell that only safelySetData can
> modify m_data pointer. But that is not possible in C++ I think?
 
AFAIK only by way of inheriting that from a class like your Data. ;-)
 
 
Cheers & hth.,
 
- Alf
JiiPee <no@notvalid.com>: Sep 25 08:40PM +0100

On 25/09/2015 19:37, Paavo Helde wrote:
> get/set part. In my own code I would probably put asserts there,
> instead of just ignoring any inconsistencies (as your design appears
> to prescribe).
 
yes, debug time asserts are very good there for sure. There is nothing
to lose to do them neither.
ram@zedat.fu-berlin.de (Stefan Ram): Sep 25 03:27PM

>Now this would do the job, but its a bit difficult way to do a simple
>single variable thing.
 
I'd do it this way too. It is not difficult.
ram@zedat.fu-berlin.de (Stefan Ram): Sep 25 06:28PM

»[I]f T has a user-declared constructor (12.1), every
non-static data member of class T shall have a name
different from T.«, C++ 2015, 9.2.15.
 
(Strictly this does not /allow/ the same name for the case of
no user-declared constructor, it just does /not forbid/ it,
and I am not aware of any other place forbidding it.)
 
In the following program, the field »entity1« has a name
»entity1« that differs from the name »entity« of the class
»entity«:
 
#include <iostream>
#include <ostream>
#include <string>
 
using namespace ::std::literals;
struct entity { ::std::string entity1; };
 
int main()
{ ::entity entity{ "abc"s };
::std::cout << entity.::entity::entity1 << '\n';
::std::cout << entity.entity1 << '\n'; }
 
It prints
 
abc
abc
 
here. Now, one can change the name »entity1« into »entity«.
Now, the name of the field »entity« is the same as the name
of the class »entity«! But this should /be/ allowed since we
do not define a constructor. But the compiler now reports an
error here!

#include <iostream>
#include <ostream>
#include <string>
 
using namespace ::std::literals;
struct entity { ::std::string entity; };
 
int main()
{ ::entity entity{ "abc"s };
::std::cout << entity.::entity::entity << '\n';
::std::cout << entity.entity << '\n'; }
 
In function 'int main()':
error: cannot call constructor 'entity::entity' directly
::std::cout << entity.::entity::entity << '\n';
^
 
The compiler now thinks I want to access the constructor.
Since there is no user-declared constructor, the compiler
might think of the implicitly defined constructor.
 
(Does anyone know a place where C++ suggest this
interpretation?)
 
However, when the field is not accessed via its
fully-qualified name »::entity::entity«, but only via
its actual name »entity«, the compilers accepts the
program:
 
#include <iostream>
#include <ostream>
#include <string>
 
using namespace ::std::literals;
struct entity { ::std::string entity; };
 
int main()
{ ::entity entity{ "abc"s };
::std::cout << entity.entity << '\n';
::std::cout << entity.entity << '\n'; }
 
This now prints
 
abc
abc
 
. So maybe the C++ norm should generally forbid fields
whose name is the same as the name of the class
(not just for the case of user-declared constructors).
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: