If the arrow operator of my class returns a pointer to internal data, is it a good idea to always declare it as ref qualified and have it work solely for l-values?
template <class T>
class Dummy
{
T _data; // data lives within the class
public:
Dummy() { /* some ctor logic */ }
T* operator->() & { return &_data; }
// ^ this is the question
T const* operator->() const& { return &_data; }
// ^ this is the question
};
The reasoning behind this, is that using the arrow operator on a temporary instance would create a dangling pointer by default, since the data lives in my class.
Also, is there a canonical resource on ref qualifiers and overloading member access operators?
Note that the provided class example is purely for demo reasons, to provide a minimum example.
Related
I am trying to create a wrapper class for the std::unique_ptr, for now it just needs to support the basic operations for the unique_ptr, but in the future this would have more functionalities.
template<typename T>
class Unique {
public:
Unique(std::nullptr_t) { pointer = nullptr; }
template<typename ...Args>
Unique(Args&&... args) { pointer = std::make_unique<T>(std::forward<Args>(args)...); }
T operator*() const { return *pointer.get(); }
T* operator->() const { return pointer.get(); }
// operator=() ?
private:
std::unique_ptr<T> pointer;
};
Doing Unique<Foo> foo() works just fine, but the problem happens when I try to do Unique<Foo> bar = foo, a compiler error happens saying
error: no matching function for call to ‘Foo::Foo(Unique\<Foo\>&)’ { return unique\_ptr<\_Tp>(new \_Tp(std::forward<\_Args>(\_\_args)...)); }
How can I define a operator= to make this work?
The whole point of unique_ptr is that it is unique -- there can only be one pointer to an object and that pointer can't be copied.
If you want your class that contains a unique_ptr to be copied, you probably want it to create a new unique_ptr to a copy of the pointed at object:
template<typename T> Unique<T> &Unique<T>::operator=(const Unique<T> &a) {
if (a.pointer)
pointer = std::make_unique<T>(*a.pointer);
else
pointer.reset();
return *this;
}
This will only work if T is not a dynamic class -- if T is actually a base class and you generally have pointers to a subblass, this won't work and will slice the object (which is bad). You might be able to make something work if your dynamic base class has a clone method or something similar.
You might also want a move-assignment operator:
template<typename T> Unique<T> &Unique<T>::operator=(Unique<T> &&a) {
pointer = std::move(a.pointer);
return *this;
}
or you could put
Unique<T> &operator=(Unique<T> &&) = default;
in the class to get the compiler to create a default one for you (which would be the same as this unless there are other fields).
Turns out, as #che.wang pointed out, I actually needed a Converting Assignment Constructor based on (2) from the unique_ptr reference like:
template<typename U> Unique(Unique<U>&& other) { pointer = std::move(other.pointer); }
How can I properly implement a copy constructor for my iterator, knowing that the pointer to the data object is private? Do I need to create an accessor for this pointer? Isn't this a bad thing?
Since you define a copy constructor for an iterator inside the implementation of the iterator itself, there is no need to make the hidden pointer accessible, with or without an accessor: the copy constructor will have access to it even if it is private, so there's nothing to worry about:
template <class T>
class MyIter {
T *private_ptr;
public:
MyIter(const MyIter<T> &other) : private_ptr(other.private_ptr) {}
... // More constructors and member functions
};
All member functions of a class have access to the data members of the class. This also applies to different objects of the same type.
class Foo()
{
private:
int bar;
public:
void foobar(Foo & different) { bar = different.bar; }
};
I have a class template in which there is a function that takes an argument of the type of the class that inherits the template. I can't seem to find the right syntax to bring this about. For example, if this is my template:
// A template to promote a simple C-style struct, T_C,
// to a C++ class 'T' with constructors, destructors,
// copy and move assignment operators.
template <typename T_C> class myTemplate
{
// We could in principle create templated copy and move
// constructors and assignment operators, but they'd be
// implicitly deleted by the compiler unless we explicitly defaulted
// them: see
// http://stackoverflow.com/questions/25246573/copy-assignment-operator-defined-in-template-being-deleted-by-compiler.
// Explicitly defaulting them works well if the template is
// contained in an all-header library. However, on including
// the template-derived classes into a DLL in Visual Studio 2013
// it was found that, even when all the other methods
// in a class were properly exported, the defaulted
// template methods were not. There may be a workaround for
// this, but in the scheme of things it was thought easier
// just to dispense with the templated operators and to
// create copy and move assignment operators, as well as the
// corresponding constructors, for each derived type.
//
// We can at least simplify things a little, and force some
// consistency upon our various class definitions,
// by insisting that every relevant class defines the
// functions listed, which can then be called from the
// constructors and assignment operators to make them a bit
// more manageable.
// Tidy up all pointers etc. and return all buffers to a safe state
virtual void clear() = 0;
protected:
// Construct a 'T' from a T_C:
virtual void construct_contents(const T_C &source) = 0;
// Deep copy the contents of a T_C to a 'T'
virtual void copy_contents(const T_C &source) = 0;
// Move the contents of one object to another: for use in both the move constructor
// and the move assignment operator:
virtual void move_contents(myTemplate<T_C> &&source) = 0;
// For sure this is wrong, but I can't figure out
// what the right argument type should be
};
...and this is my class
class myClass : public myStruct, public myTemplate<myStruct>
{
public:
// Default constructor
myClass() {}
// Copy constructor taking basic C struct
myClass(const myStruct &source)
{ construct_contents(source); }
// Copy constructor taking this promoted C++ class
myClass(const myClass &source)
{ construct_contents(source); }
// Copy assignment operator taking basic C struct
MyClass & operator=(const myStruct &source)
{
copy_contents(source);
return *this;
}
// Copy assignment operator taking this promoted C++ class
MyClass & operator=(const myClass &source)
{
copy_contents(source);
return *this;
}
// Move constructor taking this promoted C++ class
myClass(myClass &&source)
{
move_contents(std::move(source));
}
// Move assignment operator taking this promoted C++ class
myClass & operator=(myClass &&source)
{
if (this != &source)
{
clear();
move_contents(std::move(source));
}
return *this;
}
// Destructor
~myClass()
{
clear();
}
// Various getters and setters for the data fields of myStruct
// ....
virtual void clear() override
{
// Stuff...
}
protected:
virtual void construct_contents(const myStruct &source) override
{
// Stuff...
}
virtual void copy_contents(const myStruct &source) override
{
// Stuff...
}
virtual void move_contents(myClass &&source) override
{
// Stuff...
}
};
...then everything works just fine except that the compiler throws an error saying (in Visual Studio 2013) 'member function declared with "override" does not override a base class member' when it encounters my definition of myClass::move_contents. I can understand why it is unhappy: 'myClass' is not only a 'myTemplate<myStruct>', but a type that jointly inherits both myTemplate<myStruct> and myStruct. What I actually need to do is to declare move_contents in the template so that the argument type is the same as the type of the derived object, in this case 'myClass'. However, I can't think of a way of specifying this in the template declaration.
My working solution is to take move_contents out of the template altogether and define a totally independent move_contents method for each separate derived type. This is all right, but doing this would block off the possibilty of pulling the move constructor and assignment operator back into the template - something I'd love to do if I can ever figure out a way of getting Visual Studio 2013 to export them properly.
The template parameter is myStruct, so the method expects an argument of type myTemplate<myStruct>, not myClass.
Declare your method with :
virtual void move_contents(myTemplate<myStruct> &&source) override
{
// Stuff...
}
I'm going to accept #quantdev's answer because he put me on the right track, but here is what eventually worked.
In my original code snippet (see my question above), I inserted an additional public virtual function into the template:
virtual T_C * baseObject() = 0;
In my definition of myClass, I overrode this as follows:
virtual myStruct * baseObject() override { return static_cast<myStruct *>(this); }
This worked because myClass inherits myStruct, so the 'this' pointer of any myClass object is always castable to a myStruct*.
Then, in my move_contents method, I was able to access the myStruct pointers to both the source and destination objects:
void move_contents(myTemplate<myStruct> && source) override
{
stuff = source.baseObject() -> stuff;
source.baseObject() -> stuff = nullptr;
// So that the buffer which my new object now
// points to isn't released when the source
// object is destroyed
}
As far as I can see, this does everything that I need.
I'd like to declare a primitive type member in a class that forbids usage of operator&(). In other words: I don't want anyone to ever take the address of this member (and possibly pass it to other classes or functions, etc.)
Is this possible without using a wrapper type?
You can declare operator&() as private which prevent the address being taken with the & prefix, but std::addressof can always be used to circumvent that. Taking the address cannot be prevented, but it can be made for difficult as a deterrent.
Assume your class is A
Put this in your class declaration
A* operator&() = delete;
Declare your member as private, and your getter doesn't return reference/pointer.
it works also for non primitive-class (with the cost of the copy)
class A
{
public:
const A* operator & () const = delete; // pre-require of OP
A* operator&() = delete; // pre-require of OP.
int getMember() const { return member; }
void setMember(int value) { member = value;}
// Other stuff.
private:
int member;
};
I have a URes class which contains a single pointer to <T>, with indirection operators -> and * overloaded so I can use the instance as a pointer directly.
However I also want to be able to pass my URes instance to functions that normally take the pointer inside the URes instance.
How do I make it so that when my URes instance object is passed to a function it is automatically cast to the pointer it contains?
The same way that you create any outbound conversion: by declaring and defining an operator.
In this case, you want a member operator T*.
Example:
template <typename T>
struct Foo {
operator T*() {
return 0;
}
};
void bar(int* p) {}
int main() {
Foo<int> f;
bar(f);
}
However, I'd recommend avoiding this and implementing a member T* get() instead. It should be an explicit step for a calling scope to obtain a pointer from your object.
You can do that by providing a conversion operator from that class to the pointer-type:
class Foo {
public:
operator int() const { // enables implicit conversion from Foo to int
}
};
Note that such implicit conversion can introduce unexpected behavior.