I overloaded the operator+ for a self written class further I deal with instances of these class via smart pointers. Now I am wondering if there isn't a better way to make use of the operator. Further I do not get how to pack them back into a shared_ptr.
class A
{
A operator + (A const & other)
{ //do some addition stuff and return new A}
};
std::shared_ptr<A> a, b;
//Currently I add them up like this
auto c = *a.get() + *b.get()
The dereference operator is overloaded for the "smart pointers".
You should add them up like this:
*a + *b
If you want a shared object with the result, you make a shared object from it:
auto c = std::make_shared<A>(*a + *b);
If you had raw pointers you would do this:
auto c = new A(*a + *b);
The similarity is not a coincidence.
On a side note, unless you really intend to share an object among multiple owners, you should not be using shared_ptr at all.
Is there a better way to add two smart pointers?
You cannot add smart pointers. What you're doing here is indirecting through smart pointers and adding the pointed objects.
The call to get() is redundant. You can indirect through the smart pointer directly: *a + *b.
Further I do not get how to pack them back into a shared_ptr
A simple way to create a shared pointer is std::make_shared.
You can implement an operator for a shared_ptr specialization:
class A
{
...
};
std::shared_ptr<A> operator+(const std::shared_ptr<A>& a1, const std::shared_ptr<A>& a2)
{
return std::make_shared<A>(*a1 + *a2);
}
and simple use
std::shared_ptr<A> a1, a2;
std::shared_ptr<A> a3 = a1 + a2;
A full example could be
class Value
{
private:
int value;
public:
Value(int value_): value(value_)
{}
Value operator+(Value other) const
{
return Value(value + other.value);
}
};
std::shared_ptr<Value> operator+(const std::shared_ptr<Value>& a, const std::shared_ptr<Value>& b)
{
return std::make_shared<Value>(*a + *b);
}
So you could use
Value a, b;
Value c = a + b;
and also
std::shared_ptr<Value> pa, pb;
std::shared_ptr<Value> pc = pa + pb;
Related
Let's say I have a class A which specifies conversion to int
struct A {
int val = 42;
operator int() const {
return val;
}
so I can use it like this:
A a;
int a_int = a;
But what if I want to use shared pointer to the class:
auto a_ptr = std::shared_ptr<A>(new A);
int a_int = a_ptr; // ???
Just like the variable with type A was implicitly converted to int I want to do the same with a smart pointer.
How can I achieve that?
UPDATE
I'm sorry maybe I asked wrong way.
The real deal is a little bit more complicated.
I use QVariant to hold std::shared_ptr.
for now I have a helper function to do that:
QVariant & operator<< (QVariant& v, const std::shared_ptr<A> & aPtr);
When I need to place my pointer to QVariant I do this:
QVariant variant = QVariant() << a_ptr;
But I want to do it automatically, something like this:
QVariant variant = a_ptr;
Have you tried it?
std::shared_ptr has the operator* and it works as one can expect: use it.
#include <memory>
struct A {
int val = 42;
operator int() const {
return val;
}
};
int main() {
auto ptr = std::make_shared<A>();
int v = *ptr;
}
Just like the variable with type A was implicitly converted to int I want to do the same with a smart pointer.
No, you think you do, but you really don't.
How can I achieve that?
You can't, and that's a good thing.
(anticipating) Any way around it?
Wrap the shared pointer into an object, like this:
#include <memory>
template<class T>
struct shared_reference
{
shared_reference(std::shared_ptr<T> pt) : _pt(std::move(pt)) {}
operator T& () {
return *_pt;
}
operator const T& () const {
return *_pt;
}
std::shared_ptr<T> _pt;
};
Its quite simple, use dereference operator:
int a_int = *a_ptr; // ???
^ ~~~
[Edit]
To make:
QVariant variant = a_ptr;
Work, You would have to add to QVariant copy constructor accepting reference to shared_ptr. And this is something you cannot do. Such statement is called Copy Initialization, first compiler tries to do conversion of a_ptr to QVariant and if it is available then copy constructor of QVariant is called with converted a_ptr. The problem is that even if you dereference a_ptr, there are two user defined conversions needed.
You can still add a cast like here:
QVariant variant = static_cast<int>(*a_ptr);
The current implementation for general swap in the standard library is something like
template <class T>
void swap(T& a, T& b) {
T c(move(a));
a = move(b);
b = move(c);
}
I'm wondering whether I can do the following instead.
template <class T>
void swap(T& a, T& b) {
unsigned char x;
auto pa = reintepret_cast<unsigned char*>(&a);
auto pb = reintepret_cast<unsigned char*>(&b);
auto pc = pa + sizeof(a);
while (pa != pc) {
x = *pa;
*pa = *pb;
*pb = x;
++pa, ++pb;
}
}
I think this implementation is better in terms of space usage, as it takes only one byte.
There are many considerations that need to be addressed when swapping classes. For POD types, swapping bytes works correctly. More complicated classes, however, may rely on invariants that byte-swapping won't respect. For example, consider a reference to a member variable:
struct Foo {
Foo() : bar{}, barRef{bar} {};
int bar;
int& barRef; // Expected to refer to the neighboring `bar`
};
int main()
{
Foo f{};
{
Foo g{};
byte_swap(f, g);
}
// `f` is now invalid: `f.barRef` is pointing to garbage
}
You have to consider that every class can define what should happen when an instance is copied or moved by it's own. Sometimes a class may do something different then just move it's bytes. Maybe the class stores a pointer which is pointing to a member of the same instance. Just copying the bytes would breake the instace then.
I also thing that it will not make much difference. It is not really noticeable when the application needs 60 bytes more.
I'm facing a problem using VC++ and Debug CRT with a DLL in development.
I have a struct like that, holding some references.
struct DATA
{
TA*& a;
TB*& b;
TC*& c;
TD*& d;
char** chars;
int num_chars;
private:
// because:
// DATA a;
// DATA b;
// a = b; // is impossible
DATA& operator=(const DATA&); // append " = delete;" for C++11
// Default ctor (private because struct should be manually constructed using malloc)
DATA(TA*& a, TB*& b, TC*& c, TD*& d)
: a(a),
b(b),
c(c),
d(d),
chars(NULL),
num_chars(0)
{}
};
and construct it like that:
DATA*& Get()
{
static struct DATA *data = (struct DATA*)malloc(sizeof(struct DATA));
return data;
}
now it should hold uninitialized ref-to-ptrs, which I want to init by:
void func(TA* a, TB* b, TC* c, TD* d)
{
Get()->a = a;
Get()->b = b;
Get()->c = c;
Get()->d = d;
...
}
which works for everything, but ref-to-ptrs..
I'm getting a INVALID_POINTER_WRITE_FILL_PATTERN_cdcdcdcd on the first Get()->a = a; when I do !analyze -v -f using WinDbg (in a remote Kernel Debugging "kd" instance)
Thanks for your help! :)
Edit: Solution
Solution is to use the points from the correct answer.
Making the c'tor public is necessary:
struct DATA
{
TA*& a;
TB*& b;
TC*& c;
TD*& d;
char** chars;
int num_chars;
// Default ctor
DATA(TA*& a, TB*& b, TC*& c, TD*& d)
: a(a),
b(b),
c(c),
d(d),
chars(NULL),
num_chars(0)
{}
private:
// because:
// DATA a;
// DATA b;
// a = b; // is impossible
DATA& operator=(const DATA&); // append " = delete;" for C++11
};
then using placement newto construct the struct:
DATA*& Get(...)
{
// ... some stuff, overloading, other init-method etc. to init and construct like:
static struct DATA *data =
new(malloc(sizeof(struct DATA))) DATA(...); // At least assign ALL references in the c'tor
return data;
}
then use it and maybe assign everything that's no reference:
void func(TA* a, TB* b, TC* c, TD* d)
{
Get(a, b, c, d);
Get()->chars = ...
...
}
free'ing the whole thing needs to be done explicitly by calling the d'tor and free , because we use placement new:
data->~DATA();
free(data);
You cannot declare references without initializing them. Your struct has no default constructor, since you explicitly declare a non-default constructor. Just allocating malloc is not sufficient to create a valid DATA object, as it is a non-POD type.
Just go ahead and try declaring a real default constructor (i.e., DATA() {}), and you'll see that this won't work because of the reference members. If you want to use malloc to allocate non-POD objects, you'll have to use a placement new.
Note that malloc() returns uninitialized memory. C++ objects need to be constructed. The way to get an object into uninitialized memory is to use placement new (this code also adds clean-up):
#include <new>
DATA*& Get()
{
static DATA *data = new(malloc(sizeof(struct DATA))) DATA(...);
static std::unique_ptr<DATA, void(*)(DATA*)> clean(data,
[](DATA* d){
d->~DATA();
free(data);
});
return data;
}
There is no way in C++ to reseat references, i.e., they need to be set during construction. Personally, I wouldn't use malloc() but rather a suitable allocation anyway:
static DATA* data(new DATA(...));
... or, as Jarod42 pointed out, actually
static DATA data(...);
return &data;
how to customise a c++ list container such that it can holds different type of struct ?
for example
struct A
{
int a;
int b;
}
struct B
{
float a;
float b;
}
#include <list>
using namespace std;
int main()
{
...
...
A a;
a.a = 1;
a.b = 2;
B b;
b.a = 123.444;
b.b = 11.222;
List.push_back(a);
List.push_back(b);
return 0;
}
Why not polymorphism and a list of pointers to the objects?
Be careful about object lifetime. The pointers in the list will become invalid once the two objects go out of scope. You can alternatively dynamically allocate (new) the two elements and delete them when you're done, then remove them from the list.
Later edit: I get the feeling you are new to C++. After studying dynamic allocation, I recommend you look up smart pointers. They lift the burden of manually managing memory by doing it themselves:
unique_ptr and
shared_ptr
You can use them inside the list instead of naked pointers.
struct Base
{
virtual ~Base(){}
};
struct A : public Base
{
int a;
int b;
};
struct B : public Base
{
float a;
float b;
};
#include <list>
using namespace std;
int main()
{
...
...
A a;
a.a = 1;
a.b = 2;
B b;
b.a = 123.444;
b.b = 11.222;
std::list<Base*> l;
l.push_back(&a);
l.push_back(&b);
return 0;
}
In some cases it makes sense to store different types in a container. C++ supports these use cases with unions, but this feature is very basic. I recommend using boost::variant instead of unions if you really need to store different types in a container. I also recommend using std::vector instead of std::list, because otherwise it doesn't make much sense to use this optimization.
Here is an example with boost::variant:
std::vector<boost::variant<A, B>> items;
A a = ...;
B b = ...;
items.push_back(a);
items.push_back(b);
struct get_length : boost::static_visitor<double>
{
double operator()(const A& f) const { return calc(f.a, f.b); }
double operator()(const B& b) const { return calc(b.a, b.b); }
double calc(double a, double b) const { return std::sqrt(a * a + b * b); }
};
for (auto&& item : items) {
double d = boost::apply_visitor(get_length(), item);
std::cout << d << '\n';
}
I suggest boost:: any. But really, does polymorphism not solve your problem?
I'm having a really hard time finding information about these kind of stuff! :(
I'm confused why this isn't working:
vector<B*> b;
vector<C*> c;
(B and C are subclasses of A)
(both are also initialized and contain elements etc etc...)
template <class First, class Second>
bool func(vector<First*>* vector1, vector<Second*>* vector2)
return vector1 == vector2;
When compiling this returns:
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
I don't see why this wouldn't work, pointers hold addresses yeah? So why don't it just compare if the two vector pointers... point to the same address(-es)?
Here's a simple example where what you're asking for won't work.
struct A{ int i; };
struct OhNoes { double d; };
struct B: public A {};
struct C: public OhNoes, public B {};
So here, B and C are both subclasses of A.
However, an instance of C is unlikely to have the same address as its B subobject.
That is, this:
C c;
B *b = &c; // valid upcast
assert(static_cast<void*>(b) == static_cast<void *>(&c));
will fail.
Your two vectors are different types and you cannot compare them.
If you want to check that you do not call func(b, b) then you can try:
template <typename T> bool func(vector<T> const & a, vector<T> const & b)
{
if (&a == &b) return false;
// do stuff
return true;
}
Unless you are doing something very strange then the pointers to two vectors of a different types will not be equal. If you try and call func with two vectors of a different type then you will get a compiler error.