Detect assignment of base class to reference pointing at derived class - c++

I'm currently investigating the interplay between polymorphic types and assignment operations. My main concern is whether or not someone might try assigning the value of a base class to an object of a derived class, which would cause problems.
From this answer I learned that the assignment operator of the base class is always hidden by the implicitely defined assignment operator of the derived class. So for assignment to a simple variable, incorrect types will cause compiler errors. However, this is not true if the assignment occurs via a reference:
class A { public: int a; };
class B : public A { public: int b; };
int main() {
A a; a.a = 1;
B b; b.a = 2; b.b = 3;
// b = a; // good: won't compile
A& c = b;
c = a; // bad: inconcistent assignment
return b.a*10 + b.b; // returns 13
}
This form of assignment would likely lead to inconcistent object state, however there is no compiler warning and the code looks non-evil to me at first glance.
Is there any established idiom to detect such issues?
I guess I only can hope for run-time detection, throwing an exception if I find such an invalid assignment. The best approach I can think of just now is a user-defined assigment operator in the base class, which uses run-time type information to ensure that this is actually a pointer to an instance of base, not to a derived class, and then does a manual member-by-member copy. This sounds like a lot of overhead, and severely impact code readability. Is there something easier?
Edit: Since the applicability of some approaches seems to depend on what I want to do, here are some details.
I have two mathematical concepts, say ring and field. Every field is a ring, but not conversely. There are several implementations for each, and they share common base classes, namely AbstractRing and AbstractField, the latter derived from the former. Now I try to implement easy-to-write by-reference semantics based on std::shared_ptr. So my Ring class contains a std::shared_ptr<AbstractRing> holding its implementation, and a bunch of methods forwarding to that. I'd like to write Field as inheriting from Ring so I don't have to repeat those methods. The methods specific to a field would simply cast the pointer to AbstractField, and I'd like to do that cast statically. I can ensure that the pointer is actually an AbstractField at construction, but I'm worried that someone will assign a Ring to a Ring& which is actually a Field, thus breaking my assumed invariant about the contained shared pointer.

Since the assignment to a downcast type reference can't be detected at compile time I would suggest a dynamic solution. It's an unusual case and I'd usually be against this, but using a virtual assignment operator might be required.
class Ring {
virtual Ring& operator = ( const Ring& ring ) {
/* Do ring assignment stuff. */
return *this;
}
};
class Field {
virtual Ring& operator = ( const Ring& ring ) {
/* Trying to assign a Ring to a Field. */
throw someTypeError();
}
virtual Field& operator = ( const Field& field ) {
/* Allow assignment of complete fields. */
return *this;
}
};
This is probably the most sensible approach.
An alternative may be to create a template class for references that can keep track of this and simply forbid the usage of basic pointers * and references &. A templated solution may be trickier to implement correctly but would allow static typechecking that forbids the downcast. Here's a basic version that at least for me correctly gives a compilation error with "noDerivs( b )" being the origin of the error, using GCC 4.8 and the -std=c++11 flag (for static_assert).
#include <type_traits>
template<class T>
struct CompleteRef {
T& ref;
template<class S>
CompleteRef( S& ref ) : ref( ref ) {
static_assert( std::is_same<T,S>::value, "Downcasting not allowed" );
}
T& get() const { return ref; }
};
class A { int a; };
class B : public A { int b; };
void noDerivs( CompleteRef<A> a_ref ) {
A& a = a_ref.get();
}
int main() {
A a;
B b;
noDerivs( a );
noDerivs( b );
return 0;
}
This specific template can still be fooled if the user first creates a reference of his own and passes that as an argument. In the end, guarding your users from doing stupid things is an hopeless endeavor. Sometimes all you can do is give a fair warning and present a detailed best-practice documentation.

Related

Is there a way to simulate downcasting by reference

So, I have something along the lines of these structs:
struct Generic {}
struct Specific : Generic {}
At some point I have the the need to downcast, ie:
Specific s = (Specific) GetGenericData();
This is a problem because I get error messages stating that no user-defined cast was available.
I can change the code to be:
Specific s = (*(Specific *)&GetGenericData())
or using reinterpret_cast, it would be:
Specific s = *reinterpret_cast<Specific *>(&GetGenericData());
But, is there a way to make this cleaner? Perhaps using a macro or template?
I looked at this post C++ covariant templates, and I think it has some similarities, but not sure how to rewrite it for my case. I really don't want to define things as SmartPtr. I would rather keep things as the objects they are.
It looks like GetGenericData() from your usage returns a Generic by-value, in which case a cast to Specific will be unsafe due to object slicing.
To do what you want to do, you should make it return a pointer or reference:
Generic* GetGenericData();
Generic& GetGenericDataRef();
And then you can perform a cast:
// safe, returns nullptr if it's not actually a Specific*
auto safe = dynamic_cast<Specific*>(GetGenericData());
// for references, this will throw std::bad_cast
// if you try the wrong type
auto& safe_ref = dynamic_cast<Specific&>(GetGenericDataRef());
// unsafe, undefined behavior if it's the wrong type,
// but faster if it is
auto unsafe = static_cast<Specific*>(GetGenericData());
I assume here that your data is simple.
struct Generic {
int x=0;
int y=0;
};
struct Specific:Generic{
int z=0;
explicit Specific(Generic const&o):Generic(o){}
// boilerplate, some may not be needed, but good habit:
Specific()=default;
Specific(Specific const&)=default;
Specific(Specific &&)=default;
Specific& operator=(Specific const&)=default;
Specific& operator=(Specific &&)=default;
};
and bob is your uncle. It is somewhat important that int z hae a default initializer, so we don't have to repeat it in the from-parent ctor.
I made thr ctor explicit so it will be called only explicitly, instead of by accident.
This is a suitable solution for simple data.
So the first step is to realize you have a dynamic state problem. The nature of the state you store changes based off dynamic information.
struct GenericState { virtual ~GenericState() {} }; // data in here
struct Generic;
template<class D>
struct GenericBase {
D& self() { return *static_cast<D&>(*this); }
D const& self() const { return *static_cast<D&>(*this); }
// code to interact with GenericState here via self().pImpl
// if you have `virtual` behavior, have a non-virtual method forward to
// a `virtual` method in GenericState.
};
struct Generic:GenericBase<Generic> {
// ctors go here, creates a GenericState in the pImpl below, or whatever
~GenericState() {} // not virtual
private:
friend struct GenericBase<Generic>;
std::unique_ptr<GenericState> pImpl;
};
struct SpecificState : GenericState {
// specific stuff in here, including possible virtual method overrides
};
struct Specific : GenericBase<Specific> {
// different ctors, creates a SpecificState in a pImpl
// upcast operators:
operator Generic() && { /* move pImpl into return value */ }
operator Generic() const& { /* copy pImpl into return value */ }
private:
friend struct GenericBase<Specific>;
std::unique_ptr<SpecificState> pImpl;
};
If you want the ability to copy, implement a virtual GenericState* clone() const method in GenericState, and in SpecificState override it covariantly.
What I have done here is regularized the type (or semiregularized if we don't support move). The Specific and Generic types are unrelated, but their back end implementation details (GenericState and SpecificState) are related.
Interface duplication is avoided mostly via CRTP and GenericBase.
Downcasting now can either involve a dynamic check or not. You go through the pImpl and cast it over. If done in an rvalue context, it moves -- if in an lvalue context, it copies.
You could use shared pointers instead of unique pointers if you prefer. That would permit non-copy non-move based casting.
Ok, after some additional study, I am wondering if what is wrong with doing this:
struct Generic {}
struct Specific : Generic {
Specific( const Generic &obj ) : Generic(obj) {}
}
Correct me if I am wrong, but this works using the implicit copy constructors.
Assuming that is the case, I can avoid having to write one and does perform the casting automatically, and I can now write:
Specific s = GetGenericData();
Granted, for large objects, this is probably not a good idea, but for smaller ones, will this be a "correct" solution?

Providing strong guarantees in methods/classes that were not designed with exception-safety in mind

I have a design problem. Let's start by saying that this code
struct Trial{
const double a;
Trial(double a_) : a(a_){}
};
int main(){
Trial t1(1.);
Trial t2(2.);
t1 = t2;
}
doesn't compile, because Trial::operator= isn't built by default by the compiler, since Trial::a is const. And that's pretty much obvious.
Now the point is this, code first
struct Trial{
const double a;
Trial(double a_) : a(a_){}
};
struct MyClass : private Trial{
MyClass(double a_) : Trial(a_), i(0) {};
void wannaBeStrongGuaranteeMemberFunction(){
MyClass old(i);
bool failed = true;
//... try to perform operations here
if(failed)
*this = old;
}
unsigned int i;
};
int main(){
MyClass m1(1.);
m1.wannaBeStrongGuaranteeMemberFunction();
}
I need to provide strong exception safety for some of the methods of a class, which is derived from Trial. Such methods perform an endless series of operations on an endless series of members (i in the example) and this makes it unpractical to "manually" revert the operations. Therefore I decided that it's better to perform a copy of the whole class and copy it back if anything fails.
Small parenthesis, the code is just an example. Everything is much more complex in the legacy real-world code.
In this example, copying just i would be fine, but this is not the case in the real code.
Moreover, the operations have multiple (and complex) paths of executions, so that it would be a pain to "read" them as "transactions".
Moreover, I'm implementing this using scope guards, so exceptions are being managed correctly in the real code.
Of course the whole thing doesn't compile, because of the line *this = old.
How would you solve the problem/address the issue?
The obvious answer is to modify Trial so that it supports
assignment as well. Barring that, and if the only reason you
want to support assignment is to provide the strong guarantee,
you could implement your own assignment operator, preferrably
private, which ignored the base class; since you know that the
two base classes will be identical, there's no need to assign
between them.
Note that the strong guarantee more often involves swapping than
assignment. Which doesn't change the problem: you can't swap
two versions of Trial, either. You'ld most likely have
something like:
class MyClass : private Trial
{
class Protected
{
bool myCommitted;
MyClass* myOwner;
MyClass myInstance;
public:
MyClass( MyClass& owner )
: myCommitted( false )
, myOwner( &owner )
, myInstance( owner )
{
}
~MyClass()
{
if ( myCommitted ) {
myOwner->swap( myInstance );
}
}
MyClass& instance() { return myInstance; }
void commit() { myCommitted = true; }
};
public:
void protectedFunc()
{
Protected p( *this );
p.instance().unprotecedVersionOfFunc();
// ...
p.commit();
}
Any exception will leave the object unchanged. (You can, of
course, reverse the logic, making the modifications on this,
and swapping if uncommitted.) The advantage of doing things
this way is that you will also "undo" any changes in memory
allocation, etc.
Finally: do you really want to use a const member in Trial.
The usual way of implementing this would be to make a
non-const but private, and only provide a getter. This means
that Trial::a is effectively const, except for complete
assignment.

How to work around 'const' definition in library

I'm using a library that defines some data type classes usually implemented as tight wrappers around a std::vector<>. The type hierarchy is several layers deep, mostly only adding elaborated constructors.
My problem: the base class defines its std::vector as private (which is fine), but only adds an accessor method as const. The derived class doesn't even have access to it. The library looks like this (shorted for clarity):
template <class T> class BaseList
{
public:
BaseList (const T data0) : data_ (1) {
data_[0] = data0; }
const T & operator[] (const size_t nr) const {
// does out off bounds check here
return data_[nr]; }
private:
std::vector<T> data_;
}
class FancyClass : public BaseList<SomeEnumType>
{
public:
FancyClass (const SomeOtherEnumType data0)
: BaseList<SomeEnumType> ( static_cast<SomeEnumType> (data))
{}
}
Now as I see it, the const definition is completely bogus. No internal method relies on the vector really being constant, neither do I in my external code.
What I like to do is simply this:
strukt MyType {
FancyClass myData;
bool otherData;
}
int main() {
MyType storage = {FancyClass(0), false};
storage.myData[0] = 5;
}
Which of course doesn't work because of the const-ness. ("assignment of read-only location")
With the responsibility completely on my side: is there some const_cast magic I could do to make this structure writable?
The only other possibility I know would be to completely replicate the type hierarchy in my code, but this would still leave me with either a lot of casts or a toFancyClass() function to call whenever I interface library code.
Any Ideas? Thanks!
(Please don't comment on the code quality of the library. If I could change that, I wouldn't be asking this question ...)
Now as I see it, the const definition is completely bogus. No internal method relies on the vector really being constant, neither do I in my external code.
The const qualifier on a method doesn't mean it relies on the vector being constant. It means that the method will not modify the state of the object. It is added so that the following code will compile.
void f(const FancyClass a)
{
cout<<a[0];
}
The above code will not above compile without the const qualifiers on the [] method.
Anyway, the following should work
SomeEnumType & r = const_cast<SomeEnumType &>(storage.myData[0]);
r = b;
where b is an enum of type SomeEnumType
However if your storage object is actually a const object, then it will lead to undefined behaviour.
The simplest would be to add non-const version of the operator[]. Otherwise, you might cause an UB by casting away the constness with using const_cast.
You can throw away the constness like this :
int main() {
MyType storage = {FancyClass(0), false};
const_cast< SomeEnumType& >( storage.myData[0] ) = 5;
}
Normally operator[] comes in pairs of a mutable and a const version.. (See: Operator overloading)
Of course there is a const_cast-based solution, but it involves undefined behaviour (you're not allowed to change a value after casting away constness!)

Shortest and best way to "reinitialize"/clean a class instance

I will keep it short and just show you a code example:
class myClass
{
public:
myClass();
int a;
int b;
int c;
}
// In the myClass.cpp or whatever
myClass::myClass( )
{
a = 0;
b = 0;
c = 0;
}
Okay. If I know have an instance of myClass and set some random garbage to a, b and c.
What is the best way to reset them all to the state after the class constructor was called, so: 0, 0 and 0?
I came up with this way:
myClass emptyInstance;
myUsedInstance = emptyInstance; // Ewww.. code smell?
Or..
myUsedInstance.a = 0; myUsedInstance.c = 0; myUsedInstance.c = 0;
I think you know what I want, is there any better way to achieve this?
myUsedInstance = myClass();
C++11 is very efficient if you use this form; the move assignment operator will take care of manually cleaning each member.
You can implement clear as a generic function for any swappable type. (A type being swappable is common and done implicitly in C++0x with a move constructor. If you have a copy constructor and assignment operator that behave appropriately, then your type is automatically swappable in current C++. You can customize swapping for your types easily, too.)
template<class C>
C& clear(C& container) {
C empty;
using std::swap;
swap(empty, container);
return container;
}
This requires the least work from you, even though it may appear slightly more complicated, because it only has to be done once and then works just about everywhere. It uses the empty-swap idiom to account for classes (such as std::vector) which don't clear everything on assignment.
If you have seen that the swap is a performance bottleneck (which would be rare), specialize it (without having to change any use of clear!) in myClass's header:
template<>
myClass& clear<myClass>(myClass& container) {
container = myClass();
return container;
}
If myClass is a template, you cannot partially specialize clear, but you can overload it (again in the class header):
template<class T>
myClass<T>& clear(myClass<T>& container) {
container = myClass<T>();
return container;
}
The reason to define such specialization or overload in myClass's header is to make it easy to avoid violating the ODR by having them available in one place and not in another. (I.e. they are always available if myClass is available.)
Just assign to a default-constructed class, like you have. Just use a temporary, though:
struct foo
{
int a, b, c;
foo() :
a(), b(), c()
{} // use initializer lists
};
foo f;
f.a = f.b =f.c = 1;
f = foo(); // reset
You may want to consider using placement new. This will allow you to use the same memory but call the constructor again.
Don't forget to call the destructor before using placement new, however.
Well, there is a much much more elegant way:
Create a vector of your classes with single element and update that element calling the
constructor:
std::vector<your_class> YourClasses;
YourClasses.resize(1);
YourClasses[0] = YourClass(...);
YourClass &y_c = *(&YourClasses[0]);
// do whatever you do with y_c
// and then if you want to re-initialize, do this
YourClasses[0] = YourClass(...);
// and voilla, continue working with resetted y_c

Hidden Features of C++? [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 11 years ago.
Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
No C++ love when it comes to the "hidden features of" line of questions? Figured I would throw it out there. What are some of the hidden features of C++?
Most C++ programmers are familiar with the ternary operator:
x = (y < 0) ? 10 : 20;
However, they don't realize that it can be used as an lvalue:
(a == 0 ? a : b) = 1;
which is shorthand for
if (a == 0)
a = 1;
else
b = 1;
Use with caution :-)
You can put URIs into C++ source without error. For example:
void foo() {
http://stackoverflow.com/
int bar = 4;
...
}
Pointer arithmetics.
C++ programmers prefer to avoid pointers because of the bugs that can be introduced.
The coolest C++ I've ever seen though? Analog literals.
I agree with most posts there: C++ is a multi-paradigm language, so the "hidden" features you'll find (other than "undefined behaviours" that you should avoid at all cost) are clever uses of facilities.
Most of those facilities are not build-in features of the language, but library-based ones.
The most important is the RAII, often ignored for years by C++ developers coming from the C world. Operator overloading is often a misunderstood feature that enable both array-like behaviour (subscript operator), pointer like operations (smart pointers) and build-in-like operations (multiplying matrices.
The use of exception is often difficult, but with some work, can produce really robust code through exception safety specifications (including code that won't fail, or that will have a commit-like features that is that will succeed, or revert back to its original state).
The most famous of "hidden" feature of C++ is template metaprogramming, as it enables you to have your program partially (or totally) executed at compile-time instead of runtime. This is difficult, though, and you must have a solid grasp on templates before trying it.
Other make uses of the multiple paradigm to produce "ways of programming" outside of C++'s ancestor, that is, C.
By using functors, you can simulate functions, with the additional type-safety and being stateful. Using the command pattern, you can delay code execution. Most other design patterns can be easily and efficiently implemented in C++ to produce alternative coding styles not supposed to be inside the list of "official C++ paradigms".
By using templates, you can produce code that will work on most types, including not the one you thought at first. You can increase type safety,too (like an automated typesafe malloc/realloc/free). C++ object features are really powerful (and thus, dangerous if used carelessly), but even the dynamic polymorphism have its static version in C++: the CRTP.
I have found that most "Effective C++"-type books from Scott Meyers or "Exceptional C++"-type books from Herb Sutter to be both easy to read, and quite treasures of info on known and less known features of C++.
Among my preferred is one that should make the hair of any Java programmer rise from horror: In C++, the most object-oriented way to add a feature to an object is through a non-member non-friend function, instead of a member-function (i.e. class method), because:
In C++, a class' interface is both its member-functions and the non-member functions in the same namespace
non-friend non-member functions have no privileged access to the class internal. As such, using a member function over a non-member non-friend one will weaken the class' encapsulation.
This never fails to surprise even experienced developers.
(Source: Among others, Herb Sutter's online Guru of the Week #84: http://www.gotw.ca/gotw/084.htm )
One language feature that I consider to be somewhat hidden, because I had never heard about it throughout my entire time in school, is the namespace alias. It wasn't brought to my attention until I ran into examples of it in the boost documentation. Of course, now that I know about it you can find it in any standard C++ reference.
namespace fs = boost::filesystem;
fs::path myPath( strPath, fs::native );
Not only can variables be declared in the init part of a for loop, but also classes and functions.
for(struct { int a; float b; } loop = { 1, 2 }; ...; ...) {
...
}
That allows for multiple variables of differing types.
The array operator is associative.
A[8] is a synonym for *(A + 8). Since addition is associative, that can be rewritten as *(8 + A), which is a synonym for..... 8[A]
You didn't say useful... :-)
One thing that's little known is that unions can be templates too:
template<typename From, typename To>
union union_cast {
From from;
To to;
union_cast(From from)
:from(from) { }
To getTo() const { return to; }
};
And they can have constructors and member functions too. Just nothing that has to do with inheritance (including virtual functions).
C++ is a standard, there shouldn't be any hidden features...
C++ is a multi-paradigm language, you can bet your last money on there being hidden features. One example out of many: template metaprogramming. Nobody in the standards committee intended there to be a Turing-complete sublanguage that gets executed at compile-time.
Another hidden feature that doesn't work in C is the functionality of the unary + operator. You can use it to promote and decay all sorts of things
Converting an Enumeration to an integer
+AnEnumeratorValue
And your enumerator value that previously had its enumeration type now has the perfect integer type that can fit its value. Manually, you would hardly know that type! This is needed for example when you want to implement an overloaded operator for your enumeration.
Get the value out of a variable
You have to use a class that uses an in-class static initializer without an out of class definition, but sometimes it fails to link? The operator may help to create a temporary without making assumptins or dependencies on its type
struct Foo {
static int const value = 42;
};
// This does something interesting...
template<typename T>
void f(T const&);
int main() {
// fails to link - tries to get the address of "Foo::value"!
f(Foo::value);
// works - pass a temporary value
f(+Foo::value);
}
Decay an array to a pointer
Do you want to pass two pointers to a function, but it just won't work? The operator may help
// This does something interesting...
template<typename T>
void f(T const& a, T const& b);
int main() {
int a[2];
int b[3];
f(a, b); // won't work! different values for "T"!
f(+a, +b); // works! T is "int*" both time
}
Lifetime of temporaries bound to const references is one that few people know about. Or at least it's my favorite piece of C++ knowledge that most people don't know about.
const MyClass& x = MyClass(); // temporary exists as long as x is in scope
A nice feature that isn't used often is the function-wide try-catch block:
int Function()
try
{
// do something here
return 42;
}
catch(...)
{
return -1;
}
Main usage would be to translate exception to other exception class and rethrow, or to translate between exceptions and return-based error code handling.
Many know of the identity / id metafunction, but there is a nice usecase for it for non-template cases: Ease writing declarations:
// void (*f)(); // same
id<void()>::type *f;
// void (*f(void(*p)()))(int); // same
id<void(int)>::type *f(id<void()>::type *p);
// int (*p)[2] = new int[10][2]; // same
id<int[2]>::type *p = new int[10][2];
// void (C::*p)(int) = 0; // same
id<void(int)>::type C::*p = 0;
It helps decrypting C++ declarations greatly!
// boost::identity is pretty much the same
template<typename T>
struct id { typedef T type; };
A quite hidden feature is that you can define variables within an if condition, and its scope will span only over the if, and its else blocks:
if(int * p = getPointer()) {
// do something
}
Some macros use that, for example to provide some "locked" scope like this:
struct MutexLocker {
MutexLocker(Mutex&);
~MutexLocker();
operator bool() const { return false; }
private:
Mutex &m;
};
#define locked(mutex) if(MutexLocker const& lock = MutexLocker(mutex)) {} else
void someCriticalPath() {
locked(myLocker) { /* ... */ }
}
Also BOOST_FOREACH uses it under the hood. To complete this, it's not only possible in an if, but also in a switch:
switch(int value = getIt()) {
// ...
}
and in a while loop:
while(SomeThing t = getSomeThing()) {
// ...
}
(and also in a for condition). But i'm not too sure whether these are all that useful :)
Preventing comma operator from calling operator overloads
Sometimes you make valid use of the comma operator, but you want to ensure that no user defined comma operator gets into the way, because for instance you rely on sequence points between the left and right side or want to make sure nothing interferes with the desired action. This is where void() comes into game:
for(T i, j; can_continue(i, j); ++i, void(), ++j)
do_code(i, j);
Ignore the place holders i put for the condition and code. What's important is the void(), which makes the compiler force to use the builtin comma operator. This can be useful when implementing traits classes, sometimes, too.
Array initialization in constructor.
For example in a class if we have a array of int as:
class clName
{
clName();
int a[10];
};
We can initialize all elements in the array to its default (here all elements of array to zero) in the constructor as:
clName::clName() : a()
{
}
Oooh, I can come up with a list of pet hates instead:
Destructors need to be virtual if you intend use polymorphically
Sometimes members are initialized by default, sometimes they aren't
Local clases can't be used as template parameters (makes them less useful)
exception specifiers: look useful, but aren't
function overloads hide base class functions with different signatures.
no useful standardisation on internationalisation (portable standard wide charset, anyone? We'll have to wait until C++0x)
On the plus side
hidden feature: function try blocks. Unfortunately I haven't found a use for it. Yes I know why they added it, but you have to rethrow in a constructor which makes it pointless.
It's worth looking carefully at the STL guarantees about iterator validity after container modification, which can let you make some slightly nicer loops.
Boost - it's hardly a secret but it's worth using.
Return value optimisation (not obvious, but it's specifically allowed by the standard)
Functors aka function objects aka operator(). This is used extensively by the STL. not really a secret, but is a nifty side effect of operator overloading and templates.
You can access protected data and function members of any class, without undefined behavior, and with expected semantics. Read on to see how. Read also the defect report about this.
Normally, C++ forbids you to access non-static protected members of a class's object, even if that class is your base class
struct A {
protected:
int a;
};
struct B : A {
// error: can't access protected member
static int get(A &x) { return x.a; }
};
struct C : A { };
That's forbidden: You and the compiler don't know what the reference actually points at. It could be a C object, in which case class B has no business and clue about its data. Such access is only granted if x is a reference to a derived class or one derived from it. And it could allow arbitrary piece of code to read any protected member by just making up a "throw-away" class that reads out members, for example of std::stack:
void f(std::stack<int> &s) {
// now, let's decide to mess with that stack!
struct pillager : std::stack<int> {
static std::deque<int> &get(std::stack<int> &s) {
// error: stack<int>::c is protected
return s.c;
}
};
// haha, now let's inspect the stack's middle elements!
std::deque<int> &d = pillager::get(s);
}
Surely, as you see this would cause way too much damage. But now, member pointers allow circumventing this protection! The key point is that the type of a member pointer is bound to the class that actually contains said member - not to the class that you specified when taking the address. This allows us to circumvent checking
struct A {
protected:
int a;
};
struct B : A {
// valid: *can* access protected member
static int get(A &x) { return x.*(&B::a); }
};
struct C : A { };
And of course, it also works with the std::stack example.
void f(std::stack<int> &s) {
// now, let's decide to mess with that stack!
struct pillager : std::stack<int> {
static std::deque<int> &get(std::stack<int> &s) {
return s.*(pillager::c);
}
};
// haha, now let's inspect the stack's middle elements!
std::deque<int> &d = pillager::get(s);
}
That's going to be even easier with a using declaration in the derived class, which makes the member name public and refers to the member of the base class.
void f(std::stack<int> &s) {
// now, let's decide to mess with that stack!
struct pillager : std::stack<int> {
using std::stack<int>::c;
};
// haha, now let's inspect the stack's middle elements!
std::deque<int> &d = s.*(&pillager::c);
}
Another hidden feature is that you can call class objects that can be converted to function pointers or references. Overload resolution is done on the result of them, and arguments are perfectly forwarded.
template<typename Func1, typename Func2>
class callable {
Func1 *m_f1;
Func2 *m_f2;
public:
callable(Func1 *f1, Func2 *f2):m_f1(f1), m_f2(f2) { }
operator Func1*() { return m_f1; }
operator Func2*() { return m_f2; }
};
void foo(int i) { std::cout << "foo: " << i << std::endl; }
void bar(long il) { std::cout << "bar: " << il << std::endl; }
int main() {
callable<void(int), void(long)> c(foo, bar);
c(42); // calls foo
c(42L); // calls bar
}
These are called "surrogate call functions".
Hidden features:
Pure virtual functions can have implementation. Common example, pure virtual destructor.
If a function throws an exception not listed in its exception specifications, but the function has std::bad_exception in its exception specification, the exception is converted into std::bad_exception and thrown automatically. That way you will at least know that a bad_exception was thrown. Read more here.
function try blocks
The template keyword in disambiguating typedefs in a class template. If the name of a member template specialization appears after a ., ->, or :: operator, and that name has explicitly qualified template parameters, prefix the member template name with the keyword template. Read more here.
function parameter defaults can be changed at runtime. Read more here.
A[i] works as good as i[A]
Temporary instances of a class can be modified! A non-const member function can be invoked on a temporary object. For example:
struct Bar {
void modify() {}
}
int main (void) {
Bar().modify(); /* non-const function invoked on a temporary. */
}
Read more here.
If two different types are present before and after the : in the ternary (?:) operator expression, then the resulting type of the expression is the one that is the most general of the two. For example:
void foo (int) {}
void foo (double) {}
struct X {
X (double d = 0.0) {}
};
void foo (X) {}
int main(void) {
int i = 1;
foo(i ? 0 : 0.0); // calls foo(double)
X x;
foo(i ? 0.0 : x); // calls foo(X)
}
map::operator[] creates entry if key is missing and returns reference to default-constructed entry value. So you can write:
map<int, string> m;
string& s = m[42]; // no need for map::find()
if (s.empty()) { // assuming we never store empty values in m
s.assign(...);
}
cout << s;
I'm amazed at how many C++ programmers don't know this.
Putting functions or variables in a nameless namespace deprecates the use of static to restrict them to file scope.
Defining ordinary friend functions in class templates needs special attention:
template <typename T>
class Creator {
friend void appear() { // a new function ::appear(), but it doesn't
… // exist until Creator is instantiated
}
};
Creator<void> miracle; // ::appear() is created at this point
Creator<double> oops; // ERROR: ::appear() is created a second time!
In this example, two different instantiations create two identical definitions—a direct violation of the ODR
We must therefore make sure the template parameters of the class template appear in the type of any friend function defined in that template (unless we want to prevent more than one instantiation of a class template in a particular file, but this is rather unlikely). Let's apply this to a variation of our previous example:
template <typename T>
class Creator {
friend void feed(Creator<T>*){ // every T generates a different
… // function ::feed()
}
};
Creator<void> one; // generates ::feed(Creator<void>*)
Creator<double> two; // generates ::feed(Creator<double>*)
Disclaimer: I have pasted this section from C++ Templates: The Complete Guide / Section 8.4
void functions can return void values
Little known, but the following code is fine
void f() { }
void g() { return f(); }
Aswell as the following weird looking one
void f() { return (void)"i'm discarded"; }
Knowing about this, you can take advantage in some areas. One example: void functions can't return a value but you can also not just return nothing, because they may be instantiated with non-void. Instead of storing the value into a local variable, which will cause an error for void, just return a value directly
template<typename T>
struct sample {
// assume f<T> may return void
T dosomething() { return f<T>(); }
// better than T t = f<T>(); /* ... */ return t; !
};
Read a file into a vector of strings:
vector<string> V;
copy(istream_iterator<string>(cin), istream_iterator<string>(),
back_inserter(V));
istream_iterator
You can template bitfields.
template <size_t X, size_t Y>
struct bitfield
{
char left : X;
char right : Y;
};
I have yet to come up with any purpose for this, but it sure as heck surprised me.
One of the most interesting grammars of any programming languages.
Three of these things belong together, and two are something altogether different...
SomeType t = u;
SomeType t(u);
SomeType t();
SomeType t;
SomeType t(SomeType(u));
All but the third and fifth define a SomeType object on the stack and initialize it (with u in the first two case, and the default constructor in the fourth. The third is declaring a function that takes no parameters and returns a SomeType. The fifth is similarly declaring a function that takes one parameter by value of type SomeType named u.
Getting rid of forward declarations:
struct global
{
void main()
{
a = 1;
b();
}
int a;
void b(){}
}
singleton;
Writing switch-statements with ?: operators:
string result =
a==0 ? "zero" :
a==1 ? "one" :
a==2 ? "two" :
0;
Doing everything on a single line:
void a();
int b();
float c = (a(),b(),1.0f);
Zeroing structs without memset:
FStruct s = {0};
Normalizing/wrapping angle- and time-values:
int angle = (short)((+180+30)*65536/360) * 360/65536; //==-150
Assigning references:
struct ref
{
int& r;
ref(int& r):r(r){}
};
int b;
ref a(b);
int c;
*(int**)&a = &c;
The ternary conditional operator ?: requires its second and third operand to have "agreeable" types (speaking informally). But this requirement has one exception (pun intended): either the second or third operand can be a throw expression (which has type void), regardless of the type of the other operand.
In other words, one can write the following pefrectly valid C++ expressions using the ?: operator
i = a > b ? a : throw something();
BTW, the fact that throw expression is actually an expression (of type void) and not a statement is another little-known feature of C++ language. This means, among other things, that the following code is perfectly valid
void foo()
{
return throw something();
}
although there's not much point in doing it this way (maybe in some generic template code this might come handy).
The dominance rule is useful, but little known. It says that even if in a non-unique path through a base-class lattice, name-lookup for a partially hidden member is unique if the member belongs to a virtual base-class:
struct A { void f() { } };
struct B : virtual A { void f() { cout << "B!"; } };
struct C : virtual A { };
// name-lookup sees B::f and A::f, but B::f dominates over A::f !
struct D : B, C { void g() { f(); } };
I've used this to implement alignment-support that automatically figures out the strictest alignment by means of the dominance rule.
This does not only apply to virtual functions, but also to typedef names, static/non-virtual members and anything else. I've seen it used to implement overwritable traits in meta-programs.