Operator overloading behavior based on member - c++

Struct A
{
int* ptr;
int operator+=(const A& other)
{
// if(ptr == nullptr)
// { DoSomething(); }
// else { ...}
}
...
}
Is it possible to have a template operator+= (on a NON-template Class A) in order to resolve that if statement at compile time?
EDIT: I have a bunch of API's, all with the signature:
A funcX()
{
// lot of A's overloaded operators calls
return A;
}
Now, I need to use those API's with a new type, that shares a lot of members with A and add a new one (a smart pointer).
Since all the A funcX() return by value, I cannot derive my new type from A and call A funcX() with the derived type (slicing).
So my solution is to add a smart pointer to A, and a constructor in A that initializes that pointer.
So now I get to use all the API's, and when A is constructed with its new constructor (that initializes the pointer), I want all the operators to have a different behaviour than the existing one.
I was looking into some templates tricks to avoid the cost of checking the pointer inside each operator, although from the comments it doesn't seem possible to achieve it.

Related

C++ std::move a pointer

I have a C++ framework which I provide to my users, who should use a templated wrapper I wrote with their own implementation as the templated type.
The wrapper acts as an RAII class and it holds a pointer to an implementation of the user's class.
To make the user's code clean and neat (in my opinion) I provide a cast operator which converts my wrapper to the pointer it holds. This way (along with some other overloads) the user can use my wrapper as if it is a pointer (much like a shared_ptr).
I came across a corner case where a user calls a function, which takes a pointer to his implementation class, using std::move on my wrapper. Here's an example of what it looks like:
#include <iostream>
using namespace std;
struct my_interface {
virtual int bar() = 0;
};
template <typename T>
struct my_base : public my_interface {
int bar() { return 4; }
};
struct my_impl : public my_base<int> {};
template <typename T>
struct my_wrapper {
my_wrapper(T* t) {
m_ptr = t;
}
operator T*() {
return m_ptr;
}
private:
T* m_ptr;
};
void foo(my_interface* a) {
std::cout << a->bar() << std::endl;
}
int main()
{
my_impl* impl = new my_impl();
my_wrapper<my_impl> wrapper(impl);
foo(std::move(wrapper));
//foo(wrapper);
return 0;
}
[This is ofcourse just an example of the case, and there are more methods in the wrapper, but I'm pretty sure that don't play a role here in this case]
The user, as would I, expect that if std::move was called on the wrapper, then after the call to foo the wrapper will be empty (or at least modified as if it was moved), but in reality the only method being invoked before foo is the cast operator.
Is there a way to make the call to foo distinguishable between the two calls to foo i.e when calling with and without std::move?
EDIT
Thanks to the Mooing Duck's comment I found a way that my_wrapper knows which call is required, but I'm really not sure this is the best method to go with and will appreciate comments on this as well:
Instead of the previous cast operator use the following two:
operator T*() & {
return m_ptr;
}
operator T*() &&{
//Do something
return m_ptr;
}
now operator T*() && is called when calling with std::move and operator T*() & is called when calling without it.
The user, as would I, expect that if std::move was called on the wrapper, then after the call to foo the wrapper will be empty (or at least modified as if it was moved)
Your expectation is wrong. It will only be modified if a move happens, i.e. if ownership of some kind of resource is transferred. But calling foo doesn't do anything like that, because it just gets access to the pointer held inside the wrapper. Calling std::move doesn't do anything except cast its argument to an rvalue, which doesn't alter it. Some function which accepts an rvalue by reference might modify it, so std::move enables that, but it doesn't do that itself. If you don't pass the rvalue to such a function then no modification takes place.
If you really want to make it empty you can add an overload to do that:
template<typename T>
void foo(my_wrapper<T>&& w) {
foo(static_cast<my_interface*>(w));
w = my_wrapper<T>{}; // leave it empty
}
But ... why? Why should it do that?
The wrapper isn't left empty if you do:
my_wrapper<my_impl> w(new my_impl);
my_wrapper<my_impl> w2 = std::move(w);
And isn't left empty by:
my_wrapper<my_impl> w(new my_impl);
my_wrapper<my_impl> w2;
w2 = std::move(w);
If copying an rvalue wrapper doesn't leave it empty, why should simply accessing its member leave it empty? That makes no sense.
Even if your wrapper has a move constructor and move assignment operator so that the examples above do leave w empty, that still doesn't mean that accessing the member of an rvalue object should modify the object. Why does it make any logical difference whether the operator T* conversion is done to an lvalue or an rvalue?
(Also, are you really sure that having implicit conversions both to and from the wrapped pointer type is a good idea? Hint: it's not a good idea. In general prefer to make your conversions explicit, especially if you're dealing with pointers to dynamically-allocated objects.)

How to implement simple class with variant field in c++

I want to implement class which let's say have field key and class A or B.
The argument in constructor in this class is array of chars.
The constructor pseudocode would take a look at first char, if it is exual to 0x00 it will create class A object,
otherwise it will create class B object - both classes will take the array of chars as argument.
Anyway I want to keep this implementation simple. I don't want to use boost::Variant unless I really need to,
and also I don't want to implement sth like this Implementing a "variant" class
because I am not familiar with template programming and I think my problem can be implemented in much simpler way.
For POD types, we have union (but the union won't remember which type you assigned, so also store this separately). This won't work for non-POD types. The major reason is because C++ doesn't know which one it should create upon construction / delete upon deletion of the union.
But a union can be used to hold pointers to the actual types. Then you have to care about construction and deletion yourself.
You could create something like this, which wraps this pointer-union and adds a convenient interface. Detailed explanation is written in the comments:
class EitherAorB {
// We have to remember what we actually created:
enum Which {
A_Type,
B_Type
} m_which;
// We store either a pointer to an A or to a B. Note that this union only
// stores one pointer which is reused to interpret it as an A*, B* or void*:
union {
A *a;
B *b;
void *untyped; // Accessing the same pointer without looking at the type
} m_ptr;
// Additional stuff you want to store besides A and B
const char *m_key;
public:
EitherAorB(const char *key) {
// Decision: Which type do we want to create?
m_which = key[0] == 0 ? A_Type : B_Type;
// Create the type (the cast to void* make the pointer "untyped"):
m_ptr.untyped = m_which == A_Type ? (void*)new A() : (void*)new B();
// Store additional stuff
m_key = key;
}
~EitherAorB() {
// Since we stored the actual contents outside and point to them,
// we have to free the memory. For this, we have to care about the
// type again, so the correct destructor will be chosen. Deleting
// the untyped pointer won't work here.
if (m_which == A_Type) delete m_ptr.a;
if (m_which == B_Type) delete m_ptr.b;
}
// These two functions can be used to query which type is stored.
bool hasA() const {
return m_which == A_Type;
}
bool hasB() const {
return m_which == B_Type;
}
// These two functions can be used to query the pointers to the actual types.
// I made them return a null pointer if the wrong getter was used.
A *getA() {
return m_which == A_Type ? m_ptr.a : 0;
}
B *getB() {
return m_which == B_Type ? m_ptr.b : 0;
}
}
Note that this implementation will lack memory if you copy an instance of EitherAorB. To fix this, either disable copying (by making the copy constructor and assignment operator private or disable them in C++11 using = delete), or implement the copy constructor and assignment operator which will deeply copy the pointee.
You said you aren't familiar with template programming. Making this implementation templated isn't difficult. Just put template<typename A, typename B> before the whole class definition; it should then work out of the box. However, don't move the implementations in .cpp files in this case; best is to keep them inlined as I wrote it.
Then, A and B aren't types but placeholders you assign types in your client code. I'd then rename the tempalte class to just Either, so your type names become something like Either<This, That>.

Why is it "dumb to override the & operator and return *this*"?

Granted, I cannot think of any reason why I would ever want to override the unary & operator, but in https://stackoverflow.com/a/4542813/368896 the poster states, in regards to some class X:
...unless X does something really dumb, like overloading the unary &
to return this
(NOTE: I assume this comment refers to the fact of the & operator returning this, not the fact of overriding the & operator itself.)
As I thought about that comment, it occurred to me that "returning this" is exactly what the & operator does - even in cases of multiple inheritance.
Given that one might never want to override the unary & operator, nonetheless why would it be dumb to have it return this (if you did decide to override it)?
it occurred to me that "returning this" is exactly what the & operator does
You're right about that, although C++ also forbids taking the address of a temporary object.
In the context of the question you reference, which is about determining if an object is a temporary:
If you implement your own operator & that returns this, you will bypass this protection by telling the compiler that &(expression) is always valid. Consider:
struct foo
{
};
struct bar
{
bar* operator&()
{
return this;
}
};
template <typename T>
void test(const T*)
{
// no temporaries, can't take address of temporary...right?
}
int main()
{
foo x;
test(&x); // okay, x is an lvalue
/*
test(&(foo())); // not okay, cannot take address of temporary
*/
bar y;
test(&y); // still okay, y is an lvalue
test(&(bar())); // huh?! not taking address of temporary, calling operator&
}
It indeed has very limited uses.
One usecase for example are smartpointers as they are often used in Direct3D to wrap IUnknown objects.
I assume you're not familiar with Direct3D, so I'll talk a bit more on that.
Many Direct3D classes derive from IUnknown and after they've been used one must call Release. Yep, D3D internally uses reference counting. People tend to forget calling Release and it really is very tedious. So what one does is wrapping the IUnknown into a smartpointer which will do the release behind the scenes.
smart_pointer<ID3D11Device> device = // ..
Thus, by stating &device you don't want the address of smart_pointer<ID3D11Device>, you want the address of ID3D11Device.
template <class T>
class com_ptr
{
private:
T *inst;
public:
// many other methods/overloadings
T** operator & ()
{
return &inst;
}
};
Bottom line: This way, you can invoke Release in the destructor and don't have to care about it in the rest of the code.
Bottom line 2: The better way to do it is to add a get() method which returns the intern object.
T** get()
{
return &inst;
}

How arrow-> operator overloading works internally in c++?

I understand the normal operator overloading. Compiler can translate them to method call directly. I am not very clear about the -> operator. I was writing my first custom iterator and I felt like the need of -> operator. I took a look at the stl source code and implemented my own like it:
MyClass* MyClassIterator::operator->() const
{
//m_iterator is a map<int, MyClass>::iterator in my code.
return &(m_iterator->second);
}
Then I can use an instance of MyClassIterator like:
myClassIterator->APublicMethodInMyClass().
Looks like the compiler does two steps here.
1. Call the ->() method the get a temporary MyClass* variable.
2. Call the APublicMethodInMyClass on the temp variable use its -> operator.
Is my understanding correct?
The operator-> has special semantics in the language in that, when overloaded, it reapplies itself to the result. While the rest of the operators are applied only once, operator-> will be applied by the compiler as many times as needed to get to a raw pointer and once more to access the memory referred by that pointer.
struct A { void foo(); };
struct B { A* operator->(); };
struct C { B operator->(); };
struct D { C operator->(); };
int main() {
D d;
d->foo();
}
In the previous example, in the expression d->foo() the compiler will take the object d and apply operator-> to it, which yields an object of type C, it will then reapply the operator to get an instance of B, reapply and get to A*, after which it will dereference the object and get to the pointed data.
d->foo();
// expands to:
// (*d.operator->().operator->().operator->()).foo();
// D C B A*
myClassIterator->APublicMethodInMyClass()
is nothing but the following:
myClassIterator.operator->()->APublicMethodInMyClass()
The first call to the overloaded operator-> gets you a pointer of some type which has an accessible (from your call-site) member function called APublicMethodInMyClass(). The usual function look-up rules are followed to resolve APublicMethodInMyClass(), of course, depending on whether it is a virtual or not.
There is not necessarily a temporary variable; the compiler may or may not copy the pointer returned by &(m_iterator->second). In all probability, this will be optimized away. No temporary objects of type MyClass will be created though.
The usual caveats also do apply to m_iterator -- make sure that your calls do not access an invalidated iterator (i.e. if you are using vector for example).

C++ "smart pointer" template that auto-converts to bare pointer but can't be explicitly deleted

I am working in a very large legacy C++ code base which shall remain nameless. Being a legacy code base, it passes raw pointers around all over the place. But we are gradually trying to modernize it and so there are some smart pointer templates as well. These smart pointers (unlike, say, Boost's scoped_ptr) have an implicit conversion to the raw pointer, so that you can pass one of them into a routine that takes a raw pointer without having to write .get(). A big downside of this is that you can also accidentally use one in a delete statement, and then you have a double free bug, which can be a real pain to track down.
Is there a way to modify the template so that it still has the implicit conversion to the raw pointer, but causes a compile error if used in a delete statement? Like this:
#include <my_scoped_ptr>
struct A {};
extern void f(A*);
struct B
{
scoped_ptr<A> a;
B();
~B();
};
B::B()
: a(new A)
{
f(a); // this should compile
}
B::~B()
{
delete a; // this should NOT compile
}
The Standard says
The operand shall have a pointer type, or a class type having a single conversion function (12.3.2) to a pointer type. If the operand has a class type, the operand is converted to a pointer type by calling the above-mentioned conversion function, and the converted operand is used in place of the original operand for the remainder of this section.
You can (ab)-use the absence of overload resolution by declaring a const version of the conversion function. On a conforming compiler that's enough to make it not work anymore with delete:
struct A {
operator int*() { return 0; }
operator int*() const { return 0; }
};
int main() {
A a;
int *p = a; // works
delete a; // doesn't work
}
Results in the following
[js#HOST2 cpp]$ clang++ main1.cpp
main1.cpp:9:3: error: ambiguous conversion of delete expression of type 'A' to a pointer
delete a; // doesn't work
^ ~
main1.cpp:2:3: note: candidate function
operator int*() { return 0; }
^
main1.cpp:3:3: note: candidate function
operator int*() const { return 0; }
^
1 error generated.
On compilers that are less conforming in that regard (EDG/Comeau, GCC) you can make the conversion function a template. delete does not expect a particular type, so this would work:
template<typename T>
operator T*() { return /* ... */ }
However, this has the downside that your smartpointer is now convertible to any pointer-type. Although the actual conversion is still typechecked, but this won't rule out conversions up-front but rather give a compile time error much later. Sadly, SFINAE does not seem to be possible with conversion functions in C++03 :) A different way is to return a private nested type pointer from the other function
struct A {
operator int*() { return 0; }
private:
struct nested { };
operator nested*() { return 0; }
};
The only problem now is with a conversion to void*, in which case both conversion functions are equally viable. A work-around suggested by #Luther is to return a function pointer type from the other conversion function, which works with both GCC and Comeau and gets rid of the void* problem while having no other problems on the usual conversion paths, unlike the template solution
struct A {
operator int*() { return 0; }
private:
typedef void fty();
operator fty*() { return 0; }
};
Notice that these workarounds are only needed for compilers that are not conforming, though.
There isn't a way to stop one and not the other. Anywhere it can be implicitly converted to a pointer for a function call, it can be implicitly converted for a delete expression.
Your best bet is to remove the conversion function. Your situation is exactly why user-defined conversion operators are dangerous and shouldn't be used often.
I'm wrong. :(
You can use a technique presented by Boost, but my concern is that you're allowing implicit conversions from a smart pointer to a raw pointer, which is generally frowned upon on. Besides, users can call delete on a pointer obtained by the -> operator, so there's really nothing you can do to prevent a determined idiot to work around whatever mechanism you come up with.
You really should just implement a get() method instead of providing operator T*() so that at least calls to delete smartptr will not compile. Non-idiots should be able to figure out that there's probably a reason why that won't work.
Yes, it's more work to type out LegacyFunc(smartptr.get()) than LegacyFunc(smartptr), but the former is preferred since it makes it explicit and prevents unexpected conversions from happening, like delete smartptr.
What if you have functions like this:
void LegacyOwnPointer(SomeType* ptr);
where the function will store the pointer somewhere? This will screw up the smart pointer, because now it's not aware that something else is owning the raw pointer.
Either way, you have some work to do. Smart pointers are like raw pointers, but they are not the same, so you can't just find-and-replace all instances of T* and replace it with my_scoped_ptr<T> and expect it to work just as well as before.
have not thought much about this but ... Can you provide an overload for operator delete which is strongly-typed for instances of your template class such that when the code is included compilation fails? if this is in your header file then implicit conversion in calls to delete should be prevented in favour of a call to your overload.
operator delete(my_scoped_ptr)
{
//... uncompilable code goes here
}
Apologies if this turns out to be a stupid idea.
I can see where you do not want to do a massive application of .get()'s. Have you ever consider a much smaller replacement of delete's?
struct A
{
friend static void Delete( A* p) { delete p; }
private:
~A(){}
};
struct B
{
};
int main()
{
delete new B(); //ok
Delete( new A ); //ok
delete new A; //compiler error
return (0);
}