Is it possible to change the address of my current struct using the -- or ++ operator, i.e.:
mystruct* test = existing_mystruct;
test++ // instead of using: test = test->next_p;
I was trying to use this, but it seems to be const and gives me an Error: assignment to this (anachronism):
struct mystruct {
mystruct* next_p;
mystruct* prev_p;
void operatorplusplus () { this = next_p; }
void operatorminusminus() { this = prev_p; }
};
Objects have a constant address in memory while they exist.
You may copy them to a new address, however.
What you try to do is advance in a linked list. And it may be done with those operators if you overload them. But you will need to define that in a special handle class to wrap over the list nodes.
EDIT
The code for what I describe will look somewhat like this:
class mylist
{
struct mynode
{
//data
mynode* next;
mynode* prev;
} *curr;
public:
mylist& operator++() {curr = curr->next; return *this;}
};
Naturally you'd wanna do boundry checks and such, but that's the general idea.
No. this pointer is of type mystruct * const, which means its address is unchangeable.
Related
When declaring a pointer variable, is there ever a use for more than one asterisk? I know when you want to have a pointer point to another you would use multiple, but just to clarify, when declaring you still only put one?
Weard things: an example of 3 asterisks:
const char **stringArray;
now, if you want to allocate this array in a function as an argument, you need the following:
void stringAllocator(const char ***stringArray, int size) {
*stringArray = (const char **) malloc(size);
}
...
stringAllocator (&stringArry, 20);
...
So, you can imagine more than 3 as well, though i had never saw more than 4 :-)
an a bit weirder stuff in c++ using stars in combination with &
void stringAllocator(const char **&stringArray, int size) {
stringArray = (const char **) malloc(size);
}
...
stringAllocator (stringArry, 20);
...
In the above case works as a star reduction technique. It does the same as the first examle
When declaring a pointer variable, is there ever a use for more than one asterisk?
Sure, there are uses for declarations of pointer to pointer variables.
Let's suppose you have a function that does allocate some class instance internally, but needs to indicate failure at the same time. You can give it a signature like
bool CreateSomeType(SomeType** pointerToSomeTypePointer) {
try {
*pointerToSomeTypePointer = new SomeType();
}
catch(...) {
return false;
}
return true;
}
and being called like this
SomeType* ptr = nullptr;
if(CreateSomeType(&ptr)) {
// Use ptr
// ...
delete ptr;
}
else {
// Log failure
}
A common use case of two stars is when a function has to alter a pointer value, e.g. in ADT implementations like "Stack".
Though this design is more C than C++ (in C++ you can use other mechanisms like references), see the following example. I wrote it in "C"-style (even if you mentioned C++):
struct node {
int x;
struct node* next;
};
// this one works:
void insertBeforeHead(node** head, int value) {
struct node* newNode = (struct node*)malloc(sizeof(struct node));
newNode->next = *head;
newNode->x = value;
*head = newNode; // alters the pointer value of the caller
}
// this one does not work:
void insertBeforeHead2(node* head, int value) {
struct node* newNode = (struct node*)malloc(new Node);
newNode->next = head;
newNode->x = value;
head = newNode; // alters only the local copy of the pointer value
}
int main () {
struct node* mainHead = NULL;
insertBeforeHead(&mainHead,10); // changes the value of mainHead
insertBeforeHead2(mainHead,20); // does not change the value of mainHead, althouth it should.
}
#include <iostream>
#include <string>
#include <cstdlib>
#include <cassert>
#include <ctime>
#include <map>
using namespace std;
struct SBLnode {
string name;
SBLnode *next;
SBLnode * left, * right;
};
struct Queue {
SBLnode * first, * last;
};
typedef SBLnode* BST;
struct SBL {
Queue q;
BST root;
};
void SBL_init (SBL& sbl) {
sbl = NULL;
}
I keep getting the following error in GCC when compiling...
error: no match for ‘operator=’ (operand types are ‘SBL’ and ‘long int’)
sbl = NULL;
^
This error basically is for the line sbl = NULL and it would be great if someone could explain to me exactly what that error actually means.
It can't find the operator= for SBL &SBL::operator=(const long int &rhs). There is a better practice. One option is to use a pointer and set it to NULL. NULL evaluates to 0. There is no operator which assigns an int intriniscally to your SBL struct object.
Or define a const static instance of the struct with the initial values and then simply assign this value to your variable whenever you want to reset it.
For example:
static const struct SBL EmptyStruct;
This uses static initialization to set the initial values.
Then, in init you can write:
sbl = EmptyStruct;
Note: Have to compile with -fpermissive in gcc or set EmptyStruct = { }. The reason why you have to set -fpermissive is listed here for GCC 4.6. GCC 4.4 needs EmptyStruct = { }.
Here is your program running. Initially it prints "initial" twice and on the third time, it prints empty string. Meaning, it was set to nothing by the assignment in the init function.
int main()
{
struct SBLnode initial;
initial.name = "initial";
struct Queue q;
q.first = &initial;
cout << q.first->name << endl;
struct SBL testInit;
testInit.q = q;
SBL_init(testInit);
cout << testInit.q.first->name << endl;
return 0;
}
http://ideone.com/Ecm6I9
void SBL_init (SBL& sbl) {
sbl = NULL;
}
Others have already pointed out why that line doesn't compile. Perhaps I can suggest an alternative solution. Instead of providing an init function, why not give all of your structures constructors like so? Is there some reason that you can't provide those? The operator= and copy constructor don't need to be defined if shallow copying of pointers is what you want. Since nodes typically need to be moved around I'm guessing that a shallow copy is fine. You can certainly use the nullptr if using c++ 11 rather than 0. I'm not a big fan of the NULL macro and opinions often vary with regards to NULL.
struct SBL {
SBL() : root(0) {}
Queue q;
BST root;
};
struct Queue {
Queue() : first(0), last(0) {}
SBLnode * first, * last;
};
NULL is a macro which expands to the integer literal 0. There is no intrinsic or user-defined operator which can assign an integer to an object of type SBL.
It looks like you are treating sbl as a pointer; but it is not a pointer, it is a reference.
You probably wanted to write this instead:
void SBL_init (SBL& sbl) {
sbl.root = NULL;
}
This initializes sbl by nulling out its member pointers.
As others have commented, nullptr is preferred in C++11:
void SBL_init (SBL& sbl) {
sbl.root = nullptr;
}
This error means that operator= , which is a function, is not defined in struct SBL. It is required when you write
sbl = NULL;
Solution:
provide SBL& operator=( const long int& i); in struct SBL.
In fact I think that you would like something alike SBL& operator=( BST b):
struct SBL {
Queue q;
BST root;
SBL& operator=( BST b) {
root = b;
return *this;
}
};
It is trying to find an assignment operator that has the form
SBL &SBL::operator=(const long int &rhs):#
and cannot find one.
I guess you were thinking about the pointers.
I have a linked list program,in which I see a lot of -> operators, but I don't know what they do.I searched about them here and there but all I found was that that is a point to member operator and that it does something ( I didn't completely understand what and why ).Here is a code snippet from the linked list, can you explain to me how this operator works?
#include <iostream>
using namespace std;
template<class T>
class List{
struct Element{
T data_;
Element* next_;
Element* prev_;
Element(T val)
:data_(val),
next_(NULL),
prev_(NULL)
{}
};
Element* head_;
So this is the structure I am using and below is a simple push_back function.
void push_back(T val){
Element* newElement = new Element(val);
Element* back = head_->prev_;
back->next_ = newElement;
newElement->prev_ = back;
newElement->next_ = head_;
head_->next_ = newElement;
}
int main(){
List<int> l;
l.push_back(40);
return 0;
}
Examples would be greatly appreciated.
By default, the -> operator is shorthand for dereferencing the pointer and accessing a member.
The C
For example, given the declaration Element* back, then back->next is equivalent to (*back).next.
EDIT:
From Kernighan and Ritchie's "The C Programming Language":
Pointers to structures are so frequently used that an alternative notation is provided as a shorthand. If p is
a pointer to a structure, then
p->member-of-structure
refers to the particular member.
-> usually Just works like this
foo->bar() ====> (*foo).bar()
This is all it does in your example.
However it can be overloaded per class so you can use it on things like shared_ptr. The only restriction is that you can only overload it to return a different pointer to dereference. Eg
class Foo {
int* super_special_ptr;
public:
int* operator->(){ return super_special_ptr; }
};
I've got a linked list where I save data, and a pointer to next node, Node<T>* next, like this:
template <class T>
struct Node
{
T data;
Node<T>* next;
};
The thing is I want to put in this a post-increment operator, so it returns the previous value of my node, but increment the reference. So if I do this
Node<int>* someNode = someList.SomeNode();
Node<int>* tmp = someNode++;
tmp would be the original someNode value, but someNode would be someNode->next.
is it possible to put an operator in the struct? I've tried to, and searched how to do it, but as I don't deal with operators I don't know how to do.
You cannot add member function to basic type like pointer.
What are you trying to define is an iterator. Use wrapper class over your node pointer to succeed:
template <class T>
struct NodeIterator
{
NodeIterator(Node<T>* current) : current(current) {}
NodeIterator& operator ++() { current = current->next; return *this; }
NodeIterator operator ++(int) {
NodeIterator retVal = *this;
++(*this);
return retVal;
}
T* operator-> () const { return ¤t->data; }
T& operator * () const { return current->data; }
Node<T>* current;
};
See std::slist<> implementation for references. Look at template<typename _Tp> struct _List_iterator. Reading STL implementation is better than many books.
Usage:
NodeIterator<T> it = &node;
++it;
T& t = *it;
Node<T>& operator++(int) {…}
is the member you want to implement.
For your code to work, you'd need to be able to define operator++ for your pointer class. That's not allowed, though. You're welcome to define some other named function, though. For example:
template <typename Node>
Node goto_next(Node& node) {
Node result = node;
node = node->next;
return result;
}
Then you can use it like this:
Node<int>* tmp = goto_next(someNode);
Another option is to provide a real iterator class instead of just using a pointer:
Node<int>::iterator someNode = someList.begin();
Node<int>::iterator tmp = someNode++;
Make your iterator keep a Node<T>* member, and make the ++ operator update that internal pointer before it returns a copy of the iterator object.
You really don't want to do that. The idea of using ++ on a pointer is dangerously close to the common iterator pattern. You should just go the full distance and make a real iterator class. Think of std::list<T>::iterator.
Iterators are very lightweight wrappers to give a sensible interface to a node pointer, which provides things like operator ++ to move to the next node, and overloads operator -> to provide simple access to the node data. Converting client code from using a pointer to using an iterator is very straight-forward because the syntax is almost identical.
As an example, consider a simple data structure like a linked list. In C, it might look like:
struct Node
{
struct Node *next;
void *data;
};
void *getLastItem(struct Node*);
...
I'd like to have the same struct and functions, but with better type checking by declaring the type of the data field, which will always be a pointer to something. An example use:
Node<Thing*> list = getListOfThings();
Thing *t = list->data;
t = getLastItem(list);
...
But I don't want to generate an implementation for every type of pointer, as happens with a normal template. In other words, I want something more like a generic or parametric type from Java, ML, and other languages. I just tried the code below as a test. The untyped C-like part would eventually go in a implementation file, while the template and function declarations would be in the header file. I'm assuming they would be optimized away and I'd be left with machine code that is about the same as the C version, except it would be type-checked.
But I'm not great with C++... Is there a way to improve this, or use more idiomatic C++, perhaps template specialization?
#include <stdio.h>
struct NodeImpl
{
NodeImpl *next;
void *data;
};
void *getLastItemImpl(NodeImpl *list)
{
printf("getLastItem, non-template implementation.\n");
return 0; // not implemented yet
}
template <typename T>
struct Node
{
Node<T> *next;
T data;
};
template <typename T>
T getLastItem(Node<T> *list)
{
return (T)getLastItemImpl((NodeImpl*)list);
}
struct A { };
struct B { };
int main()
{
Node<A*> *as = new Node<A*>;
A *a = getLastItem(as);
Node<B*> *bs = new Node<B*>;
B *b = getLastItem(bs);
}
This is exactly what Boost.PointerContainer does, check its implementation. Basically what it does is implement the specialization for void*, and have any other implementation forward to it static_casting the parameters in and out.
struct Node
{
struct Node *next;
void *data;
};
void *getLastItem(struct Node*);
...
This is common for C, but not for C++. In C++ it usually looks like this:
template<typename T>
struct Node
{
struct Node *next;
T data;
};
T& getLastItem(const Node&);
...
Note the important difference -- the C version has another level of indirection in order to share implementations, while the C++ version need not do this. This means the C version has another n dynamic memory allocations, where n is the number of items in the list. Given that each allocation usually requires obtaining a global lock, often has at least 16 bytes of overhead per allocation, as well as all the overhead the memory manager brings to the party, the advantage of the C++ version is not insignificant, particularly when you include things like cache locality in the considerations.
Put another way, for Node<int>, the C++ version stores an int, while the C version stores an int *, along with a dynamic allocation for the int.
This of course discounting that a linked list is a horrendous data structure 90% of the time.
If you must use a linked list, and if you must use dynamic allocation for the data members, then your idea of "replace the pointers with void*s" is not unreasonable. However, if you have access to a C++11 compiler (VS2010, recent GCC versions, etc.), you should put in an assert that you depend on T being a pointer type, using std::is_pointer and static_assert, and you should use static_cast rather than C-style casts in your interface methods. The C style cast would let someone do Node<SomeTypeBiggerThanVoidPtr>, and it would compile, but explode at runtime.
As the other answers and comments said, use std::forward_list, or another existing library. If you refuse, this is more like I would do:
#include <stdio.h>
struct NodeImpl
{
NodeImpl *next;
void *data;
public:
// we have pointers, so fulfill the rule of three
NodeImpl() : next(NULL), data(NULL) {}
~NodeImpl() {}
NodeImpl& operator=(const NodeImpl& b) {next = b.next; data = b.data; return *this;}
// This function now a member. Also, I defined it.
void* getLastItem()
{
if (next)
return next->getLastItem();
return data;
}
void* getData() {return data;}
void setData(void* d) {data = d;}
};
// the template _inherits_ from the impl
template <typename T>
struct Node : public NodeImpl
{
Node<T> operator=(const Node<T>& b) {NodeImpl::operator=(b);}
// we "redefine" the members, but they're really just wrappers
T* getLastItem()
{ return static_cast<T*>(NodeImpl::getLastItem());}
T* getData() {return static_cast<T*>(NodeImpl::getData());}
void setData(T* d) {NodeImpl::setData(static_cast<void*>(d));}
//or, if you prefer directness...
operator T*() {return static_cast<T*>(NodeImpl::getData());}
Node<T> operator=(T* d) {NodeImpl::setData(static_cast<void*>(d));}
};
struct A { };
struct B { };
int main()
{
Node<A> as; //why were these heap allocated? The root can be on the stack
A *a = as.getLastItem();
Node<B> bs; //also, we want a each node to point to a B, not a B*
B *b = bs.getLastItem();
B* newB = new B;
bs = newB; //set the data member
newB = bs; //read the data member
}
http://ideone.com/xseYk
Keep in mind that this object doesn't encapsulate next or data really, so you have to manage all of that yourself.