how to preserve const correctness across pointers? - c++

I am trying to have a const operation on a class that is truly const - it does not change data that the class points to.
For example:
class Node{
public:
int val;
};
class V{
public:
Node * node; //what is the change that is needed here?
void const_action()const{
node->val=5; //error wanted here
}
void action(){
node->val=5; //error is not wanted here
}
};

You can use a template to enforce the const correctness on a pointer without changing the meaning or the implementation of your class:
template <typename T>
class PreseveConstPointer
{
T *t_;
public:
PreseveConstPointer(T *t = nullptr)
: t_(t)
{
}
PreseveConstPointer<T> * operator=(T *t)
{
t_ = t;
return this;
}
T* operator->()
{
return t_;
}
T const * operator->() const
{
return t_;
}
T * data()
{
return t_;
}
};
class Node{
public:
int val;
};
class V{
public:
PreseveConstPointer<Node> node;
V()
{
node = new Node;
}
~V()
{
if(node.data())
delete node.data();
}
void const_action()const{
node->val=5; // You will get an error here
}
void action(){
node->val=5; // No error here
}
};

const after a function declaration says that the function is not allowed to change any class members (except ones that are marked mutable).
Since your code doesn't change any class member, and only changes the object node points to, both function will compile.
AFAIK there's no way to prevent this. If you mark the node const, neither will compile.

You're confusing Node* const for Node const*.
An [unfortunate?] side effect of using indirection here is that constness of the pointer member has nothing to do with the actual Node on which you're operating.
If you don't need that member to be a pointer, then this is pleasingly easy:
class V
{
public:
Node node;
void const_action() const
{
node.val = 5; // error here
}
void action()
{
node.val = 5; // no error here
}
};
However, given its name, I suspect life is not that simple and you are basically out of luck.

Related

How to get pointer to new variable when using a move constructor

So I've got this code:
//movable_ptr.hpp
//Michal Cermak
template<typename T> class movable_ptr;
template<typename T> class enable_movable_ptr {
public:
//default constructor
enable_movable_ptr() {};
//move constructor and assignment
enable_movable_ptr(enable_movable_ptr<T>&& p) {
first_ = p.getFirst();
p.retarget_to(this);
};
enable_movable_ptr<T>& operator=(enable_movable_ptr<T>&& p) {
if (this != &p)
{
first_ = p.getFirst();
p.retarget_to(this);
delete &p;
}
return *this;
};
//retargets all pointers in the linked list to a new address
void retarget_to(T* p)
{
if (first_ != nullptr)
{
auto current = first_;
do
{
current->set(p);
current = current->getNext();
} while (current != first_);
}
};
movable_ptr<T>* getFirst() { return first_; };
void setFirst(movable_ptr<T>* p) { first_ = p; };
private:
movable_ptr<T>* first_ = nullptr;
};
template<typename T> class movable_ptr {
public:
//constructors and stuff...
//access to variables
T* get() {return ptr_; };
void set(T* p) { ptr_ = p; };
movable_ptr<T>* getNext() { return next_; };
void setNext(movable_ptr<T>* p) { next_ = p; };
movable_ptr<T>* getPrevious() {return prev_; };
void setPrevious(movable_ptr<T>* p) { prev_ = p; };
private:
T* ptr_ = nullptr;
movable_ptr<T>* next_ = this;
movable_ptr<T>* prev_ = this;
};
My problem is that I need to give T * to retarget_to, but I use retarget_to(this) in the move constructor and assignment in enable_movable_ptr. That passes it enable_movable_ptr<T> * instead of just T *. The thing is, I assume that T inherits from enable_movable_ptr, which will never be used directly, only through the object that inherits from it. For example:
class A : public enable_movable_ptr<A>
{
public:
int val;
A(int val) : val(val) {}
};
And then used like this:
A x(42);
A y = move(x);
In this case, this would be enable_movable_ptr<A> *, but I need something that would give me A * instead. Basically I need a pointer to the lvalue of the = operator, while inside an overload of said operator. Is there any way to do this or am I asking for something impossible?
I haven't understood your question entirely, because it's not clear what you want to achieve with this enable_movable_ptr class. I think your way of writing operator= is ill-formed. You are trying to explicitly call delete on a pointer to r-value (which may firstly be allocated on stack, and moreover probably will be destroyed later anyway via some other mechanism).
I would suggest to consider copy-and-swap approach for operator=, this would allow you to not worry about checking if you are assigning object into itself. The signature would be enable_movable_ptr<T>& operator=(enable_movable_ptr<T> other) (note passing by value).

Returning a non-const reference causes a binding reference error

I've implemented a double linked list using weak and smart pointers. The program is working but I have doubts about that const in the getPrev signature method. If I put const a the end of the method signature it will cause a binding reference error
error: binding reference of type 'std::weak_ptr<Node<Integer> >&' to 'const std::weak_ptr<Node<Integer> >' discards qualifiers
return prev;
Wasn't the purpose of that const to mark *this as const ? The return type is non-const for my understanding.
Here is the code, main.cpp:
#include <memory>
#include <iostream>
#include "DoubleLinkedList.h"
class Integer {
private:
int number;
public:
Integer(int number) : number(number) {}
int get() { return number; }
};
int main() {
DoubleLinkedList<Integer> list;
list.insert(Integer(1));
list.insert(Integer(2));
list.insert(Integer(3));
list.insert(Integer(4));
list.insert(Integer(5));
return 0;
}
DoubleLinkedList.h
#include <memory>
#include <vector>
#include <iostream>
template <typename T>
class Node {
private:
T data;
std::weak_ptr<Node> prev;
std::shared_ptr<Node> next;
public:
Node(): data(0) {}
Node(const T &object) : data(object) {};
T getData() const {
return data;
}
void setData(T data) {
Node::data = data;
}
std::weak_ptr<Node> &getPrev() const {
return prev;
}
void setPrev(const std::weak_ptr<Node> &prev) {
Node::prev = prev;
}
std::shared_ptr<Node> &getNext() {
return next;
}
void setNext(const std::shared_ptr<Node> &next) {
Node::next = next;
}
};
template <typename T>
class DoubleLinkedList {
private:
std::shared_ptr<Node<T>> header;
std::weak_ptr<Node<T>> trailer;
int size;
public:
DoubleLinkedList() : size(0) {}
void insert(const T &value) {
auto node = std::make_shared<Node<T>>(value);
if (size++ == 0) {
header = node;
} else {
auto last = trailer.lock();
last->getNext() = node;
node->getPrev() = last;
}
trailer = node;
}
};
If you are inside a const method, all the data members are considered const.
That is, inside this function:
std::weak_ptr<Node> &getPrev() const
you can imagine the member variables like this:
const T data;
const std::weak_ptr<Node> prev;
const std::shared_ptr<Node> next;
It should be clear that you cannot return a non-const reference to a const object:
const int x;
int& getX()
{
return x; // error
}
The reference would allow you to modify x even though it is const, so this is forbidden (formally: a non-const reference cannot bind to a const object).
Inside a const member function of Node, prev is a const std::weak_ptr<Node>, so a std::weak_ptr<Node>& cannot bind to it for the exact same reason.
It appears that within insert you do intend to modify node (by changing its prev value), in which case the getPrev function should not be const (because you intend to modify the object). But this kind of access should probably be reserved for the DoubleLinkedList and not some arbitrary outside user. It then becomes a question of interface design: Which parts of your code are implementation details and how those should be hidden from users? Which parts are the interface that users should interact with (with minimal opportunity for breaking things)?

Why can't I insert a const pointer to a multiset?

According to the documentation for multiset for instance see http://www.cplusplus.com/reference/set/multiset/insert/. It should be possible to insert a const value. In my example the multiset is a collection of pointers, but when I try to insert a const pointer I get an error.
template<typename Key>
struct node_key: public node_base {
node_key(Key k): _key(k) {}
virtual ~node_key() {}
const Key& key() const { return _key;}
protected:
Key _key;
void _copy_key(node_key<Key> *n) const { n->_key=_key;}
};
template <typename Compare>
struct ptr_less_key {
ptr_less_key() : _comp() {}
virtual ~ptr_less_key() {}
template <typename Pointer>
bool operator()(const Pointer& a, const Pointer& b) const { return _comp(a->key(), b->key()); }
Compare _comp;
};
int main() {
typedef node_key<int>* keyp;
std::multiset<keyp,ptr_less_key<std::less<int>>> x;
node_key<int> k(5);
const node_key<int> *p=&k;
x.insert(p); //this fails
return 0;
}
What you are currently doing: You are not trying to insert a const pointer, as you think you do, but a non-const pointer to a const element.
Change this
const node_key<int> *p=&k;
to this
node_key<int> *const p=&k;
to make the const keyword apply on the pointer rather than on what it points to.
Given
struct node {
void member();
void const_member() const;
};
consider the four declarations
node* pointer_to_node;
const node* pointer_to_const_node;
node* const const_pointer_to_node;
const node* const const_pointer_to_const_node;
There are two different aspects of constness: that of the object node and that of the pointer. The first two declare mutable pointers to either node or const node. A conversion from node* to const node* is allowed (and implicit), but not the other way around, as this would allow to modify a const node.
The second two declarations declare the respective pointers to be constant, i.e. these pointers cannot be modified (though the node pointed to by const_pointer_to_node can.
pointer_to_node->member(); // okay
pointer_to_node->const_member(); // okay
pointer_to_node = new node; // okay
pointer_to_node = const_pointer_to_node; // okay
pointer_to_node = pointer_to_const_node; // ERROR
pointer_to_const_node->member(); // ERROR
pointer_to_const_node->const_member(); // okay
pointer_to_const_node = new node; // okay
pointer_to_const_node = pointer_to_node; // okay
pointer_to_const_node = const_pointer_to_node; // okay
pointer_to_const_node = const_pointer_to_const_node; // okay
const_pointer_to_node->member(); // okay
const_pointer_to_node->const_member(); // okay
const_pointer_to_node = new node; // ERROR
const_pointer_to_node = const_pointer_to_node; // ERROR
const_pointer_to_node = pointer_to_const_node; // ERROR
const_pointer_to_const_node->member(); // ERROR
const_pointer_to_const_node->const_member(); // okay
const_pointer_to_const_node = new node; // ERROR
const_pointer_to_const_node = const_pointer_to_node; // ERROR
const_pointer_to_const_node = pointer_to_const_node; // ERROR

const and rvalue references

Im trying to write an efficient list and node classes that have minimal code to iterate over them. However I'm having difficulty fulfilling all my criteria. I want this code to be used safely in a multi-threaded environment and so if possible I want all the functions and arguments for iteration to be const to ensure no state is being written to ie its all read only. So I wrote the below classes and iteration code:
template<typename _Type_>
class Node
{
template<typename _Type_> friend class List;
public:
Node() : m_Next(NULL) {}
Node(const _Type_& value) : m_Value(value), m_Next(nullptr()) {}
const _Type_& Get() const { return m_Value; }
Node&& Next() const { return std::move(*m_Next); }
operator _Type_ () const { return m_Value; }
_Type_& operator->() { return m_Value; }
const _Type_& operator->() const { return m_Value; }
operator bool() const { return m_Next != nullptr(); }
private:
_Type_ m_Value;
Node* m_Next;
};
template<typename _Type_>
class List
{
public:
typedef Node<_Type_> Node;
List() : m_Head(NULL) {}
void AddHead( const _Type_& value )
{
Node* pNode = GE_NEW(Node, value);
pNode->m_Next = &m_Head;
m_Head = *pNode;
}
Node&& Head() const { return std::move(m_Head); }
private:
Node m_Head;
};
and the all important iteration code:
RenderTargetList::Node&& renderTarget = m_Targets.Head();
while( renderTarget )
{
if(renderTarget->Format() == format)
{
return renderTarget.Get();
}
renderTarget = renderTarget.Next();
}
But this doesn't compile as:
Node&& Head() const { return std::move(m_Head); }
returns a non const rvalue reference in a const function function ie it has to be:
const Node&& Head() const { return std::move(m_Head); }
instead, but then this doesn't work as the iteration code fails on the assignment:
renderTarget = renderTarget.Next();
because renderTarget must now be defined as:
const RenderTargetList::Node&& renderTarget = m_Targets.Head();
because head returns a const. Basically I seem to be in a right mess of const, references, lvalues and rvalues. Someone please help!
Thanks
Here's the basic version of a list class. Note that the iterator type and the node type are two distinct types. This way, the node type can own the value, and the iterator type can have pointer semantics.
I'll post this as a community wiki, as it's rather a comment than a direct answer to the question.
template<typename Type>
class List
{
private:
// note that for immutable nodes, we could store `Type const`
// and for an immutable list, `Node const* const`
struct Node
{
Type m_Value;
Node* m_pNext;
};
Node* m_pHead;
public:
class const_iterator
{
private:
Node const* m_pNode;
friend List;
const_iterator(Node* p_pNode) : m_pNode(p_pNode) {}
public:
const_iterator() : m_pNode(nullptr) {}
explicit operator bool() const
{ return m_pNode; }
const_iterator Next() const
{ return {m_pNode->m_pNext}; }
Type const& Get() const
{ return m_pNode->m_Value; }
friend bool operator!=(const_iterator const& lhs,
const_iterator const& rhs)
{
return lhs.m_pNode != rhs.m_pNode;
}
};
List() : m_pHead(nullptr) {}
~List()
{
// delete nodes
}
List(List const&) = delete; // needs to be customized
List& operator=(List const&) = delete; // this one, too
// the only function that modifies the list:
void AddHead( Type const& value )
{
Node* pNode = new Node{value, m_pHead};
m_pHead = pNode;
}
const_iterator Head() const
{ return {m_pHead}; }
};
Usage example:
#include <iostream>
int main()
{
List<int> l;
for(int i = 0; i < 10; ++i) l.AddHead(i);
auto it = l.Head();
while(it)
{
std::cout << it.Get() << ", ";
it = it.Next();
}
}
I think you are confused at to the point of const if your goal is thread safety -- const does not give you thread safe code, only considerate and well understood access patterns will give you thread safe code.
I have lost of code which is thread sfae which does not make use of const, and you will need to as well if you want to be able to keep the "AddHead" method which certainly in its current form is not thread safe.
If your code is threaded you will need to add mutex locks around the code where you are accessing shared data which could be modified or read by another thread -- the critical zones -- from your code structure these critical zones could be very short lived, so not much of a penalty.

Definition of operator->() in c++

Please tell me how the operator->() in being defined for the iterator of std::list in order to refer members of the element that is being pointed by an iterator.
EDIT:
The problem is that if you implement like this (Fred Nurk):
template<class T>
struct list {
private:
struct Node { // internal class that actually makes up the list structure
Node *prev, *next;
T data;
};
public:
struct iterator { // iterator interface to the above internal node type
T* operator->() const {
return &_node->data;
}
private:
Node *_node;
}
};
Then when you write:
struct A {
int n;
};
void f() {
list<A> L; // imagine this is filled with some data
list<A>::iterator x = L.begin();
x->n = 42;
}
Then
x->n I understand like x->operator->()n which is equivalent to (A ponter to a)n which is a nonsence. How to understand this part. Some answers tell that it is equivalent to x->operator->()->n; (instead of x->operator->()n) but I don't understand why. Please explain me this.
(hint: It returns a pointer to the element.)
The -> operator behaves as follows:
T->x; // some field
T->foo(); // some function
...is equivalent to:
T.operator->()->x;
T.operator->()->foo();
Note the re-application of -> to whatever is returned.
With many details elided, here is the gist of how it works:
template<class T>
struct list {
private:
struct Node { // internal class that actually makes up the list structure
Node *prev, *next;
T data;
};
public:
struct iterator { // iterator interface to the above internal node type
T* operator->() const {
return &_node->data;
}
private:
Node *_node;
}
};
Thus, given:
struct A {
int n;
};
void f() {
list<A> L; // imagine this is filled with some data
list<A>::iterator x = L.begin();
x->n = 42;
// x.operator->() returns an A*
// which gets -> applied again with "n"
}
Operator -> is implemented differently than the other operators in C++. The operator function is expected to return a pointer, and the -> is applied again to that pointer.
It returns pointer. Just for completeness, here is simple example:
#include <iostream>
#include <vector>
using namespace std;
template <typename T>
class SafeVectorIterator
{
vector<T> & _vec;
size_t _pos;
public:
SafeVectorIterator(vector<T> & vec) : _vec(vec), _pos(0) { }
void operator++() { ++_pos; }
void operator--() { --_pos; }
T& operator*() { return _vec.at(_pos); }
T* operator->() { return &_vec.at(_pos); }
};
struct point { int x, y; };
int main()
{
vector<point> vec;
point p = { 1, 2 };
vec.push_back(p);
vec.push_back(p);
SafeVectorIterator<point> it(vec);
++it;
it->x = 8;
cout << (*it).y << '\n';
return 0;
}