Is there a shorthand method to writing move constructors? - c++

I have a class with one strong pointer and a lot of object members. Writing copy and move constructors for an object like this involves a lot of tedious copy/pasting, however...
Is there any way to shorten this, without giving up my beautiful naked pointer? Like if I could perform the default generated move operation, with just one extra instruction to nullify the naked pointer afterwards?
class Example {
public:
Example()
: m_multiplexDevice(getDevice(B737M_mpDevice, true))
{
engageDevice(m_multiplexDevice);
}
Example(Example && other)
: m_multiplexDevice (other.m_multiplexDevice )
, m_pilotStack (std::move(other.m_pilotStack ))
, m_pasStack (std::move(other.m_pasStack ))
, m_pitchAttackLimits (std::move(other.m_pitchAttackLimits))
, m_yawToPitchBalance (std::move(other.m_yawToPitchBalance))
, m_engineBalance (std::move(other.m_engineBalance ))
{
other.m_multiplexDevice = NULL;
}
Example & operator=(Example && other) {
if (this != &other) {
// ignore that this is incorrect (not properly destroying in assignment),
// working with client code that kinda sucks
m_multiplexDevice = other.m_multiplexDevice;
m_pilotStack = std::move(other.m_pilotStack );
m_pasStack = std::move(other.m_pasStack );
m_pitchAttackLimits = std::move(other.m_yawToPitchBalance );
m_yawToPitchBalance = std::move(other.m_yawToPitchBalance );
m_engineBalance = std::move(other.m_engineBalance );
m_multiplexDevice = NULL;
}
return *this;
}
Example(const Example & other) =delete;
Example & operator=(const Example & other) =delete;
~Example() {
if (m_multiplexDevice)
disengageDevice(m_multiplexDevice);
delete m_multiplexDevice;
}
private:
char STRONG * m_multiplexDevice;
std::vector<uint32> m_pilotStack;
std::vector<uint32> m_pasStack;
std::vector<uint32> m_pitchAttackLimits;
std::vector<uint32> m_yawToPitchBalance;
std::vector<uint32> m_engineBalance;
// ... etc
};

Use a unique_ptr with a custom deleter.
#include <memory>
#include <vector>
#include <cstdint>
#define STRONG /* ??? */
void disengageDevice(char STRONG*);
#define B737M_mpDevice 1
char STRONG *getDevice(int, ...);
void engageDevice(char STRONG *);
class Example {
public:
Example()
: m_multiplexDevice(
getDevice(B737M_mpDevice, true),
deconstruct_m_multiplexDevice)
{
engageDevice(m_multiplexDevice.get());
}
static void deconstruct_m_multiplexDevice(char STRONG *p) {
if (p) {
disengageDevice(p);
delete p;
}
}
private:
std::unique_ptr<
char STRONG,
decltype(&deconstruct_m_multiplexDevice)
> m_multiplexDevice;
std::vector<uint32_t> m_pilotStack;
std::vector<uint32_t> m_pasStack;
std::vector<uint32_t> m_pitchAttackLimits;
std::vector<uint32_t> m_yawToPitchBalance;
std::vector<uint32_t> m_engineBalance;
// ... etc
};

Related

Point raw pointer to a shared_ptr

I started programming in C++ after a 1-year break, and I am having difficulties here and there (not that I really knew it before the break).
My current problem is that I don't know how to use pointers properly.
I have the following std::vector:
std::vector<std::shared_ptr<IHittable>> world;
Where IHittable is the interface of Hittable objects.
Now, in this std::vector, multiple derivations of IHittable are pushed, like Sphere, Triangle, etc.
Each of these derived classes has a function intersects() like this:
Intersection Sphere::intersects(const Ray & ray)
{
auto x = ...
...
return {x, this};
}
Intersection looks like this:
class Intersection
{
public:
Intersection(double t, IHittable * object);
[[nodiscard]] double t() const;
[[nodiscard]] IHittable * object() const;
private:
double t_;
IHittable * object_ = nullptr;
};
I really don't know how to write this code correctly.
I need to return a this pointer from the member function intersects() of an object which is itself allocated dynamically and is stored in a std::shared_ptr.
Is there a way to handle this?
Another example:
std::vector<std::shared_ptr<IHittable>> world;
world.push_back(std::make_shared<Sphere>());
auto s = Intersection(4.0, world[0]);
Should work.
PS: I could just create multiple std::vectors without std::shared_ptr:
std::vector<Sphere> spheres;
std::vector<Triangles> spheres;
...
But IMHO, it would be nice to iterate over every object at once.
PS2: I am now using shared_from_this() and most of my code works, thanks.
I think this sounds like a good fit for std::enable_shared_from_this as Remy pointed out in the comments.
I whipped up a simplified example which hopefully makes it clear how it can be used to achieve what you're after.
class Intersection;
class IHittable : public std::enable_shared_from_this<IHittable> {
public:
virtual Intersection intersects( ) = 0;
virtual void print( ) const = 0;
virtual ~IHittable( ) = default;
};
class Intersection {
public:
Intersection( std::shared_ptr<IHittable> object )
: object_{ std::move( object ) }
{ }
void print_shape( ) const {
object_->print( );
}
private:
std::shared_ptr<IHittable> object_;
};
class Square : public IHittable {
public:
Intersection intersects( ) override {
return Intersection{ shared_from_this( ) };
}
void print( ) const override {
std::cout << "Square\n";
}
};
int main( ) {
std::vector<std::shared_ptr<IHittable>> objects{
std::make_shared<Square>( ) };
const auto intersect{ objects.front( )->intersects( ) };
intersect.print_shape( );
}

How do i overload operator "[]" for vector containing my own class objects

So i got a class WayPoint (inside the namespace HHN).
And i got a class WayPointContainer.
The container got a private vector variable to store objects from the type "HHN::WayPoint"
What i want to do now is i want to overload the operator[] so i can
easy access the objects inside the vector like so:
WayPoint p1("name",1.5,2.0);
WayPointContainer c1;
c1[0] = p1 // This would add the WayPoint p1 to the vector of the container on index 0
WayPoint p2 = c1[0] // This would get the WayPoint from the vector at index 0 and copy it to p2
...
I found different implementations but they were for other types then vector or did not use a complex type inside the vector.
Here is my WayPointContainer.h
#include <vector>
#include <iostream>
#include "WayPoint.h"
#ifndef SRC_WAYPOINTCONTAINER_H_
#define SRC_WAYPOINTCONTAINER_H_
class WayPointContainer {
private:
std::vector<HHN::WayPoint>* pContainer{ nullptr };
public:
WayPointContainer();
WayPointContainer(const WayPointContainer& orig);
virtual ~WayPointContainer();
WayPointContainer& operator=(const WayPointContainer& rhs);
HHN::WayPoint& operator[](int idx) const;
void Add(const HHN::WayPoint& arg);
int Size() const;
void Print() const;
};
#endif /* SRC_WAYPOINTCONTAINER_H_ */
Here is my WayPointContainer.cpp
#include <vector>
#include "WayPointContainer.h"
#include <iostream>
using namespace std;
//Default Konstruktor
WayPointContainer::WayPointContainer() {
//Heap bereich ... new ... pContainer
pContainer = new std::vector<HHN::WayPoint>;
}
//Destruktor
WayPointContainer::~WayPointContainer() {} //TODO
//Copy Konstruktor
WayPointContainer::WayPointContainer(const WayPointContainer& orig) {
pContainer = orig.pContainer;
}
WayPointContainer& WayPointContainer::operator=(const WayPointContainer& rhs) {
if(&rhs == this) {
return *this;
}
if ( pContainer != rhs.pContainer) {
pContainer = rhs.pContainer;
}
return *this;
}
HHN::WayPoint& WayPointContainer::operator[](int idx) const {*
//invalid initialization of reference of type 'HHN::WayPoint&' from expression of type 'std::vector<HHN::WayPoint>'
return pContainer[idx];
}
void WayPointContainer::Add(const HHN::WayPoint& arg) {
pContainer->insert(pContainer->begin(), arg);
}
int WayPointContainer::Size() const {
int i = pContainer->size();
return i;
}
void WayPointContainer::Print() const {
for (auto waypoint = pContainer->begin(); waypoint != pContainer->end(); ++waypoint) {
cout << waypoint->Name();
}
}
The method i am struggling with:
HHN::WayPoint& WayPointContainer::operator[](int idx) const {*
//invalid initialization of reference of type 'HHN::WayPoint&' from expression of type 'std::vector<HHN::WayPoint>'
return pContainer[idx];
}
The Code i implemented there got the invalid initialization error described above.
So i expect to use the []-operator as described at the top but right now its not implemented or implemented with an error.
(I am also missing the Destructor for the vector "pContainer" inside the destructor of the WayPointContainer. So if thats something you know feel free to add it but thats not my question just a bonus.)
If you want i can also provide the code i got for the WayPoint class and my main.cpp i use to test it.
The error message is quite clear about the immediate problem in your operator implementation
invalid initialization of reference of type 'HHN::WayPoint&' from expression of type 'std::vector<HHN::WayPoint>'
pContainer[idx] dereferences pContainer with an offset of idx, thus the result is of type std::vector<HHN::WayPoint>.
There are two ways to solve the problem:
You either dereference the pointer and apply idx on it:
return (*pContainer)[idx];
You don't use a pointer to hold your std::vector<HHN::WayPoint> class member at all (recommended solution):
class WayPointContainer {
private:
std::vector<HHN::WayPoint> container;
// ...
};
In that case you won't need to deal with memory de-/allocation for the pointer, and can simply write your operator overload as
HHN::WayPoint& WayPointContainer::operator[](int idx) const {
return container[idx];
}

C++ disallow stack instance but allow new delete

Basically what I want is:
class MyClass{
public:
MyClass() = default;
// what should I do?
}
MyClass mc; // compile time error;
auto pmc = new MyClass; //OK
delete pmc; //OK too
I know I can make it heap-only by hiding constructor (can not new outside of the class now) or hiding destructor (can not delete outside of the class now) or hiding both. What if I don't want to introduce some new named function and just want the good old new and delete? Is it possible (even with hack)?
My "like a smart pointer, but not" idea:
#include <iostream>
class MyClass_ {
private:
/**/ MyClass_( void ) { }
/**/ ~MyClass_( void ) { }
public:
void func( void ) const { std::cout << "Hello" << std::endl; }
friend class MyClass;
} ;
class MyClass {
public:
/**/ MyClass( void ) : p( new MyClass_ ) { }
/**/ ~MyClass( void ) { delete p; }
// Tricky implementation details follow...
// The question in all cases is, who owns the MyClass_ that has been
// allocated on the heap? Do you always allocate a new one, and then
// copy the guts? (That might be expensive!) Do you change ownership?
// Then what about the other MyClass? What does it point to?
// Or do you share ownership? Then you need to ref-count so you don't
// delete too soon. (And this whole thing turns into an ordinary
// shared_ptr<MyClass_>)
/**/ MyClass( const MyClass &o ) { }
/**/ MyClass( MyClass &&o ) { }
MyClass &operator=( const MyClass &o ) { }
MyClass &operator=( MyClass &&o ) { }
MyClass_ * operator->( void ) { return p; }
const MyClass_ * operator->( void ) const { return p; }
private:
MyClass_ *p;
} ;
int
main( int, char ** )
{
MyClass a; // this will be destroyed properly
MyClass *b = new MyClass; // this will leak if you don't delete it
a->func( );
(*b)->func( );
return 0;
}
This is going to sound like not-what-you-want, but surround it in another class. That way you can enforce your storage is allocated off of the heap, and keep such details away from your API user.
A usual way would be to make your constructor private, and add some static member function (you could call it a factory or making function) which returns a pointer.
So your class would look like
class MyClass{
private:
MyClass() = default;
public:
static MyClass* make() { return new MyClass; };
// what should I do?
}
and you'll code:
auto mc = MyClass::make();
elsewhere (instead of new MyClass)
etc. However be aware of the rule of five and consider using (as return type of your MyClass::make) some smart pointer from the <memory> header.
You could also define your own smart pointer class with its own unary operator -> and operator * and your own variadic templates inspired by std::make_shared ...
just want the good old new and delete
In genuine C++11, this is frowned upon and may be considered bad style. You should avoid using explicitly new outside of your library, and adopt some smart pointer way of coding.

C++ How do I instantiate a VkSubProcess object from this header?

I'm having a hard time understanding how to instantiate a ViewKit VkSubProcess object. Manpage for this thing is here: VkSubProcess.3
I have read up enough about C++ to understand that this header describes a reference counted abstract base class and I think I more-or-less understand the concepts involved. However, my feeble attempts at actually using this thing have been unsuccessful.
My efforts lead to various compiler errors like:
"The class "RPtr_VkSubProcessRep" has no member "create"
or:
"No instance of constructor 'VkSubProcessRep::VkSubProcessRep' matches the argument list"
Could somebody be kind enough to please show how to instantiate a VkSubProcess object from this header?
For brevity I've removed from the header the functions mentioned in the manpage that come into play only after the instance has been created.
Many thanks.
#ifndef _VKPROCESS_H
#define _VKPROCESS_H
#include <signal.h>
#include <Xm/Xm.h>
#include <Vk/VkCallbackObject.h>
#include <Vk/VkBase.h>
#include <Vk/VkApp.h>
class VkSPCounted : public VkCallbackObject {
friend class VkSPRPtr_base;
int nreferences;
void addRef() { nreferences++; }
void delRef() {
if (--nreferences <= 0)
delete this;
}
public:
VkSPCounted() : VkCallbackObject() { nreferences = 0; }
virtual ~VkSPCounted();
private:
VkSPCounted(const VkSPCounted&);
VkSPCounted &operator= (const VkSPCounted&);
};
class VkSPRPtr_base : public VkBase {
public:
operator void*() { return (void *)ptr; }
VkSPRPtr_base& operator=(VkSPCounted *tp) {
if (ptr) ptr->delRef();
ptr = tp;
if (ptr) ptr->addRef();
return *this;
}
VkSPRPtr_base& operator=(const VkSPRPtr_base& r){
if (ptr) ptr->delRef();
ptr = r.ptr;
if (ptr) ptr->addRef();
return *this;
}
protected:
VkSPCounted *ptr;
VkSPRPtr_base() : VkBase() { ptr = 0; }
VkSPRPtr_base(const VkSPRPtr_base& r) : VkBase() {
ptr = r.ptr;
if (ptr) ptr->addRef();
}
VkSPRPtr_base(VkSPCounted *tp) : VkBase() {
ptr = tp;
if (ptr) ptr->addRef();
}
~VkSPRPtr_base() {
if (ptr) ptr->delRef();
}
};
class VkSubProcessRep;
class RPtr_VkSubProcessRep : public VkSPRPtr_base {
public:
RPtr_VkSubProcessRep();
RPtr_VkSubProcessRep(VkSubProcessRep *tp);
RPtr_VkSubProcessRep(const RPtr_VkSubProcessRep& that) : VkSPRPtr_base(that) {}
~RPtr_VkSubProcessRep();
RPtr_VkSubProcessRep& operator=(VkSubProcessRep *tp) {
*((VkSPRPtr_base *) this) = (VkSPCounted *) tp;
return *this;
}
VkSubProcessRep& operator *();
VkSubProcessRep *operator->();
int operator !(){ return !ptr; }
};
typedef RPtr_VkSubProcessRep VkSubProcess;
class VkSubProcessRep : public VkSPCounted {
public:
static VkSubProcess create(char* cmd,
int killChildOnExit,
int redirectIn);
/* Actually create VkSubProcess */
void run();
protected:
VkSubProcessRep(const char* prog,
char **argv,
int killChildOnExit,
int redirectIn);
~VkSubProcessRep();
private:
VkSubProcessRep(const VkSubProcessRep&);
VkSubProcessRep &operator= (const VkSubProcessRep&);
};
#endif
Well, after spending the day reading up on C++, I now know that this header describes a Reference-counted Singleton pattern. From what I have read, the static 'create()' function and the protected constructor seem to be typical for this pattern.
You might use it like so:
VkSubProcess process = VkSubProcessRep::create("ls -al", 1, 1);
process->run();

Compare the habits between move and smart pointer in C++?

In C++11/14, an object can be transfered by move or smark pointer.
(1) This is an example for move:
class MoveClass {
private:
int *tab_;
int alloc_;
void Reset() {
tab_ = nullptr;
alloc_ = 0;
}
void Release() {
if (tab_) delete[] tab_;
tab_ = nullptr;
alloc_ = 0;
}
public:
MoveClass() : tab_(nullptr), alloc_(0) {}
~MoveClass() {
Release();
}
MoveClass(MoveClass && other) : tab_( other.tab_ ), alloc_( other.alloc_ ) {
other.Reset();
}
MoveClass & operator=(MoveClass && other) {
if (this == &other) return *this;
std::swap(tab_, other.tab_);
std::swap(alloc_, other.alloc_);
return *this;
}
void DoSomething() { /*...*/ }
};
When we use this movable MoveClass, we can write code like this :
int main() {
MoveClass a;
a.DoSomething(); // now a has some memory resource
MoveClass b = std::move(a); // move a to b
return 0;
}
Always write move-constructor/move-operator= is boring, use shared_ptr/unique_ptr some times have the same effect, just like java, reference/pointer everywhere.
(2) Here is the example:
class NoMoveClass {
private:
int *tab_;
int alloc_;
void Release() {
if (tab_) delete[] tab_;
tab_ = nullptr;
alloc_ = 0;
}
public:
NoMoveClass() : tab_(nullptr), alloc_(0) {}
~NoMoveClass() {
Release();
}
MoveClass(MoveClass && other) = delete;
MoveClass & operator=(MoveClass && other) = delete;
void DoSomething() { /*...*/ }
};
We can use it like this:
int main() {
std::shared_ptr<NoMoveClass> a(new NoMoveClass());
a->DoSomething();
std::shared_ptr<NoMoveClass> b = a; // also move a to b by copy pointer.
return 0;
}
Is it a good habit to always use the 2nd one?
Why many libraries, STL use the 1st one, not the 1st one ?
Always write move-constructor/move-operator= is boring
You almost never need to write your own move constructor/assignment, because (as you mentioned) C++ supplies you with a number of basic resource managers - smart pointers, containers, smart locks etc.
By relying on those in your class you enable default move operations and that results in minimal code size as well as proper semantics:
class MoveClass {
private:
std::vector<int> data;
public:
void DoSomething() { /*...*/ }
};
Now you can use your class as in (1) or as a member in other classes, you can be sure that it has move semantics and you did it in the minimal possible amount of code.
The point is one usually only needs to implement move operations for the most low-level classes which are probably covered already by STL, or if some weird specific behavior is needed - both cases should be really rare and not result in "Always writing move-constructor/move-operator=".
Also notice that while approach (1) is unnecessarily verbose, (2) is just unacceptable - you have a resource managing class that doesn't do its job and as a result you have to wrap it in smart pointers everywhere in your code, making it harder to understand and eventually resulting in even more code than (1)