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>.
Related
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.
I've found out that unique_ptr can point to an already existing object.
For example, I can do this :
class Foo {
public:
Foo(int nb) : nb_(nb) {}
private:
int nb_;
};
int main() {
Foo f1(2);
Foo* ptr1(&f1);
unique_ptr<Foo> s_ptr1(&f1);
return 0;
}
My question is :
If I create a class with unique_ptr< Bar > as data members (where Bar is a class where the copy constructor was deleted) and a constructor that takes pointers as argument, can I prevent the user from passing an already existing object/variable as an argument (in that constructor) (i.e. force him to use the new keyword) ?
Because if he does, I won't be able to guarantee a valide state of my class objects (the user could still modify data members with their address from outside of the class) .. and I can't copy the content of Bar to another memory area.
Example :
class Bar {
public:
Bar(/* arguments */) { /* data members allocation */ }
Bar(Bar const& b) = delete;
/* Other member functions */
private:
/* data members */
};
class Bar_Ptr {
public:
Bar_Ptr(Bar* ptr) {
if (ptr != nullptr) { ptr_ = unique_ptr<Bar> (ptr); }
} /* The user can still pass the address of an already existing Bar ... */
/* Other member functions */
private:
unique_ptr<Bar> ptr_;
};
You can't prevent programmers from doing stupid things. Both std::unique_ptr and std::shared_ptr contain the option to create an instance with an existing ptr. I've even seen cases where a custom deleter is passed in order to prevent deletion. (Shared ptr is more elegant for those cases)
So if you have a pointer, you have to know the ownership of it. This is why I prefer to use std::unique_ptr, std::shared_ptr and std::weak_ptr for the 'owning' pointers, while the raw pointers represent non-owning pointers. If you propagate this to the location where the object is created, most static analyzers can tell you that you have made a mistake.
Therefore, I would rewrite the class Bar_ptr to something like:
class Bar_ptr {
public:
explicit Bar_ptr(std::unique_ptr<Bar> &&bar)
: ptr(std::move(bar)) {}
// ...
}
With this, the API of your class enforces the ownership transfer and it is up to the caller to provide a valid unique_ptr. In other words, you shouldn't worry about passing a pointer which isn't allocated.
No one prevents the caller from writing:
Bar bar{};
Bar_ptr barPtr{std::unique_ptr<Bar>{&bar}};
Though if you have a decent static analyzer or even just a code review I would expect this code from being rejected.
No you can't. You can't stop people from doing stupid stuff. Declare a templated function that returns a new object based on the templated parameter.
I've seen something similar before.
The trick is that you create a function (let's call it make_unique) that takes the object (not pointer, the object, so maybe with an implicit constructor, it can "take" the class constructor arguments) and this function will create and return the unique_ptr. Something like this:
template <class T> std::unique_ptr<T> make_unique(T b);
By the way, you can recommend people to use this function, but no one will force them doing what you recommend...
You cannot stop people from doing the wrong thing. But you can encourage them to do the right thing. Or at least, if they do the wrong thing, make it more obvious.
For example, with Bar, don't let the constructor take naked pointers. Make it take unique_ptrs, either by value or by &&. That way, you force the caller to create those unique_ptrs. You're just moving them into your member variables.
That way, if the caller does the wrong thing, the error is in the caller's code, not yours.
The answer to the question here addresses initializing a null-reset or zero struct.
How can I check equality though?
say my struct x is defined as follows:
struct MyStruct {
int a;
int b;
};
and the empty struct :
static const struct MyStruct EmptyStruct;
how do I check equality inside a function that takes a reference to a struct of type x?
void myFunction (... , MyStruct &x, ...){
//some code
if (x != EmptyStruct){ // this doesn't work (see error below)
}
//some code
}
The error I get when I try the above:
no match for 'operator!=' in 'x != EmptyStruct'
EDIT: to make it more clear I understand the error message in terms of overloading the != operator for the struct but since an EmptyStruct is a special kind, how can I deal with that?
I guess the point is that a struct of my type with a = 0 and b = 0 is not the same as the EmptyStruct which should represent null-like struct.
You really need to make up your mind whether your MyStruct is a value type or an identity type.
If it's a value type, then you want to define some part of its value as saying that it's empty:
struct MyStruct {
int x;
int y;
bool empty;
};
If it's an identity type, then you want to check for identity:
void myFunction(MyStruct &m) {
if (&m == &EmptyStruct)
// reference to EmptyStruct. Act accordingly.
}
If you need a singular value like your EmptyStruct, you might want to consider passing a (smart) pointer, and comparing to nullptr to determine whether you've received a singular value.
As a general rule, I'd avoid this type of design in general. Identity types are somewhat foreign to most C++ programmers, and singular values create special cases that you're generally better off without.
You need to overload the equality operator, testing every element of the structure.
bool MyClass::operator==(const MyClass &other) const {
... // Compare the values, and return a bool result.
}
Simply overload the operator== (or operator!=). Or (since by default all members of a struct are public), check all elements inside the structures.
Since your talking something about that your struct is "empty" - there's no such thing. When you create an object, the memory for it should be allocated automatically by the constructor. If you want to check if the passed struct is the static EmptyStruct, check the addresses of both.
Since you are taking the object by reference, I assume you want to test if the user actually passed the global EmptyStruct object as a function argument. This can be achieved easily by comparing addresses:
void foo(MyStruct & x)
{
if (&x == &EmptyStruct) { /* ... */ }
}
(This assumes that MyStruct does not overload operator&.)
It sounds like you want to test whether or not x refers to the same object as EmptyStruct, in which case you want to compare addresses:
if (&x != &EmptyStruct)
although this is a rather odd thing to do; it usually makes more sense to use a pointer, with a well-defined null value to represent "no object", if you want a nullable reference-like type.
== and != are used to compare values, not object identities, and have to be overloaded if you want to define them for class types.
I have edited this from my real code, so that it is a little easier to understand.
The base class:
class MWTypes
{
public:
virtual long get() { return (0); }
};
The derived class: (There are going to be other classes like char, double etc etc . . .)
class TypeLong : public MWTypes
{
public:
TypeLong(long& ref) : m_long(ref) {}
~TypeLong();
long get() { return m_long; }
private:
long& m_long;
};
and the storage class:
class RowSet
{
public:
void addElememnt(MWTypes elem);
MWTypes getElement();
std::vector<MWTypes> getVector() { return m_row; }
private:
std::vector<MWTypes> m_row;
};
How it is called:
for (i = 0; i < NumCols; i++) // NumCols is 3 on this instance
{
switch(CTypeArray[i]) // this is an int which identifies the type
{
case SQL_INTEGER:
{
long _long = 0;
TypeLong longObj(_long);
MWTypes *ptr = &longObj;
// some SQL code goes here that changes the value of _long,
// there is no need to include it, so this will do.
_long++;
// I now want to save the data in a vector to be returned to the user.
rowSet.addElememnt(*ptr);
///////////////////////////////////////////////
// some code happens here that is irrelevant //
///////////////////////////////////////////////
// I now want to return the typr I have saved in the vector,
// I THINK I am doing this right?
MWTypes returned = rowSet.getElement();
// lastly I want to get the value in the returned type
long foo = returned.get();
///////////////////////////////////////////////
// some code happens here that is irrelevant //
///////////////////////////////////////////////
I think I am on the right lines here. The value of 'foo' is always 0. I have a feeling this could be the way Im storing in the vector, or it could be the base virtual function, as it always returns 0.
If I remove the return in my base class I get LNK2001 errors.
MWTypes returned = rowSet.getElement();
// lastly I want to get the value in the returned type
long foo = returned.get();
should be
MWTypes* returned = &rowSet.getElement();
// lastly I want to get the value in the returned type
long foo = returned->get();
or
MWTypes& returned = rowSet.getElement(); // actually illegal, but MSVC will let you do
// lastly I want to get the value in the returned type
long foo = returned.get();
Indeed, polymorphic calls must be made via a pointer or a reference.
EDIT: this is not your only problem. The fact that the vector stores objects (and not pointers) will slice the objects and destroy their type information.
See this faq entry for additional info to help you solve your problem and understand how virtual functions are called.
The fundamental problem is that you are making copies of your objects of type MWTypes, thus losing their particular subclass. If you want to use an object of an unknown subclass of the base class, then you can only use a pointer or reference to the base type, not an actual instance of it.
Not providing an implementation of the function "get" as ascanio's code shows (making the function "pure virtual") would prevent you from being able to make this copying mistake, because the compiler would not let you instantiate the class MWTypes if you did that (it would say the class is "abstract").
You are suffering from slicing since your collection stores copies of the base type. Whenever you store something into the vector, your code just slices off the base part and it forgets its original type.
To fix this, you could store pointers to the base: std::vector<MWTypes*>, but then you have to manage your instances correctly to avoid memory leaks.
class RowSet
{
public:
// addElement assumes responsibility for the memory allocated for each 'elem'
void addElement(MWTypes* elem);
MWTypes* getElement();
std::vector<MWTypes*> getVector() { return m_row; }
// Destructor calls delete on every pointer in m_row
~RowSet();
private:
std::vector<MWTypes*> m_row;
};
Then you need to fix your code which calls addElement() to create new instances, and to get the long back again:
rowSet.getElement()->get();
You're problem lies with this function void addElememnt(MWTypes elem);. It should be either void addElememnt(MWTypes* elem); or void addElememnt(MWTypes& elem);. This is because by having an argument to be passed by-value, it loses it's polymorphism. The passing by-value calls the copy constructor of the base class and ONLY copies the contents of the base class (and the vtable) ignoring the rest from the derived class.
Also, if you need to store values of a certain base-class type, you need to consider using a list of pointers of the base-class type.
The problem lies here:
class RowSet
{
public:
void addElememnt(MWTypes elem);
You are taking elem by value, not by pointer or by reference, so the TypeLong subobject is sliced away, here: (reference: What Is The Slicing Problem in C++?)
TypeLong longObj(_long);
MWTypes *ptr = &longObj;
_long++;
rowSet.addElememnt(*ptr);
You need to change addElement to take a reference or a pointer.
Your vector, getElement, and addElememnt parts all invoke object slicing since they store the base object by value. You need to work with pointers or references in order to use runtime polymorphism.
In this case either a boost::ptr_vector or a vector of shared_ptr is probably what you want.
I have a class that should hold a reference to some data, without owning that data (i.e. the actual data is guaranteed not to go out of scope). In particular, the class cannot make a copy – the data is easily several gigabytes in size.
Now, the usual implementation (I assume) is to have a reference to the data:
struct holder_ref {
type const& value;
holder_ref(type const& value) : value(value) { }
};
(Please note that the constness has absolutely no bearing on the problem).
Now, I absolutely need this class to be assignable (i.e. have a working operator =). I thought this was a fairly common problem but I can’t remember how (if ever) I’ve solved it before.
The problem is that a reference cannot be assigned and there’s simply no way around this. The only solution I’ve come up with uses placement new in place of the assignment operator:
// x = other_x; gets replaced with:
x.~T();
new (&x) T(other_x);
Now, this works and is standard compliant. But it sure is ugly. No – inacceptable.
So I’m searching for alternatives. One idea is to use pointers, but I’m unsure whether my constructor is actually guaranteed to work (and passing a pointer is impossible due to the interface I have to adhere to):
struct holder_ptr {
type const* value;
// Is this legal?
holder_ptr(type const& value = 0) : value(&value) { }
};
But I’d rather use a reference, if at all possible. Only – how to implement the assignment operator?
struct holder_ref {
type const& value;
holder_ref(type const& value = 0) : value(value) { }
holder_ref& operator =(holder_ref const& other) {
// Now what?!
return *this;
}
};
As a test case, consider the following code:
int main() {
int const TEST1 = 23;
int const TEST2 = 13;
int const TEST3 = 42;
std::vector<holder_ptr> hptr(1);
std::vector<holder_ref> href(2);
// Variant 1. Pointer.
hptr[0] = holder_ptr(TEST1);
// Variant 2. Placement new.
href[0].~holder_ref();
new (&href[0]) holder_ref(TEST2);
// Variant 3. ???
href[1] = holder_ref(TEST3);
assert(*hptr[0].value == TEST1); // Works (?)
assert(href[0].value == TEST2); // Works
assert(href[1].value == TEST3); // BOOM!
}
(Also, just to make this clear – the type we’re talking about is non-POD and I need a standard compliant solution.)
I don't see anything wrong with using a holder_ptr. It can be implemented something like so:
struct bad_holder : std::exception { };
struct holder_ptr {
holder_ptr() : value(0) { }
holder_ptr(type const& value) : value(&value) { }
type const& get() {
if (value == 0) throw bad_holder();
return *value;
}
private:
type const* value;
};
So long as you always assign to the pointer from a reference, you know that you have a valid object (that, or you ended up with a "null reference" previously, in which case you have other, bigger problems since you'll already have invoked undefined behavior).
With this solution, the interface is implemented entirely in terms of references, but under the hood a pointer is used so that the type is assignable. The use of references in the interface ensures there are none of the concerns that come with using pointers (namely, you never have to worry whether the pointer is null).
Edit: I've updated the example to allow for the holder to be default constructible.
I'd use the pointer holder. But if you are dead set against that, how about hiding your placement new operator=:
holder_ref& operator =(holder_ref const& other) {
new (this) holder_ref(other);
return *this;
}
Is a TR1 weak_ptr standard compliant enough?