- A less important oddity - 1 Update
- How to secure member variables used in member functions? - 10 Updates
- How to secure member variables used in member functions? - 2 Updates
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:
Post a Comment