In C, we actually do
struct node *p = (node*)malloc(sizeof(node)); // casting is not necessary
p->a = 0; // first element
p->b = NULL; // second element
to dynamically allocate spaces in the memory, but how can I do this in C++ way?
Is the line below a correct guess?
node *p = new node {0, NULL};
Yes, you are correct.
Assuming node is an aggregate, your C++ version is right (modulo NULL rather than nullptr).
That being said, if these initial values are "defaults", you would conventionally write a default constructor to initialise those members for you automatically:
struct node
{
int a;
node* b;
node() : a(0), b(nullptr) {}
};
Then you'd just write:
node* p = new node;
Or, better:
auto p = std::make_unique<node>();
Or, better yet:
node n;
Default-construction has some consequences though. You may not want any constructors.
In C++ you would avoid a naked new and either create a shared/unique pointer with std::make_shared/std::make_unique in C++11/14 or encapsulate the allocation in a handle-class following the RAII idiom.
To give an example of how that would work:
class Foo {
const int i;
public:
int j;
Foo(int i) : i{i}, j{0} {}//constructor
void foo() {std::cout << i << "\n";}
};
int main() {
unique_ptr<Foo> fp = make_unique<Foo>(5);
fp->foo();
return 0;
}
In case the constructor looks a bit confusing to you, a short explanation: The colon after the constructors signature starts the initialization declaration. In this section you have to initialize const-values, but you can initialize all values there. Thus constructors, which take arguments often look like this:
Foo(ArgType1 arg1, ArgType2 arg2,...,ArgTypeN argN) :
member1(arg1), member2(arg2), ... , memberN(argN) {//empty body}
Be sure to pay attention to the rule of three/five, when writing constructors.
Related
I have this C++ struct:
struct Node {
char symbol;
unsigned int index;
vector<Node*> next;
// Constructors
Node():symbol('$'), index(0), next(0) {}
Node(char &c, const unsigned int &ind):symbol(c), index(ind), next(0) {}
// Add a new character
Node* add(char &c, const unsigned int &num) {
Node *newChar = new Node(c, num);
next.push_back(newChar);
return newChar;
}
// Destructor
~Node() {
for (int i = 0; i < next.size(); i++)
delete next[i];
}
};
(I know it might be better to make it a class but let's consider it as it is).
I'm not quite sure if I wrote the correct destructor for this. In the main function I'm using a root node:
Node *root = new Node();
Although the code won't leak memory (as long as you delete the root node in main), it isn't really optimal.
You should avoid new and delete and instead prefer smart pointers. In this case, use unique_ptr.
Also, don't create the root node on the heap, just create it normally like so:
Node root;
// use root normally
You also don't follow the rule of five properly, and you won't even need to worry about it if you used unique_ptr since you wouldn't have a custom dtor. There's also no reason to take the c and ind by ref and const ref, just pass them by value (because you don't even change them, and its as cheap passing by value as by ref for primitives).
With these changes, the code looks like this
struct Node {
char symbol;
unsigned int index;
vector<std::unique_ptr<Node>> next;
// Constructors
Node():symbol('$'), index(0){}
Node(char c, unsigned int ind):symbol(c), index(ind) {}
// Add a new character
Node* add(char c, unsigned int num) {
next.push_back(std::make_unique<Node>(c, num));
return next.back().get();
}
};
This is not a real question, since I've already solved the problem myself, but I still need some clarifications about the mechanism behind assigning an array's address to a pointer of the same type when the array is a class member of a nested class.
The following code is fully functioning, although it may lack some error_check. It is only meant to show how I made my (real) program work.
HEADER (linkedList)
class linkedList
{
public:
linkedList();
~linkedList();
int* getArray();
void forward();
private:
class listNode
{
public:
listNode();
~listNode();
friend class linkedList;
private:
int array[3];
listNode* next;
};
listNode *first;
listNode *current;
};
CPP (linkedList)
linkedList::linkedList()
{
first = new listNode;
current = first;
}
//~~~~~~~~~~~~
linkedList::~linkedList()
{
delete first;
first = 0;
current = 0;
}
//~~~~~~~~~~~~
int* linkedList::getArray()
{
if (current)
{
return &(current->array[0]);
}
}
//~~~~~~~~~~~~
void linkedList::forward()
{
if (current->next)
{
current = current->next;
}
}
//-------------------------
//-------------------------
//-------------------------
linkedList::listNode::listNode()
{
next = 0;
for (int i = 0; i < 3; i++){array[i]=((i+1)*3);}
}
//~~~~~~~~~~~~
linkedList::listNode::~listNode()
{
}
CPP (main)
#include <iostream>
#include "linked_list.h"
using namespace std;
int main()
{
linkedList list;
int *myArray;
myArray = list.getArray();
for (int i = 0; i < 3; i++){cout << myArray[i] << " ";}/**/cout << "\n\n";
return 0;
}
The real program is meant to move through a linked list made of nodes which contain 3 integer values in an array of int type, retrieve the three values and use them as parameters for some other functions.
Now, to do so I have to return the address to the first element of the array contained in the node through an accessor.
Apparently, the only way to do it is by returning the reference to the first element of the array in the node to which the linkedList's member variable current points to:
return &(current->array[0]);.
Why?
I've got to this solution through trial and error with very little knowlegde of the reasons that brought me to build this expression as it is.
Usually, when you want to assign the address of an array to a pointer, you just do so:
int main()
{
int array[3];
int* pArray;
pArray = array;
}
And that's it, because the name of the array itself is enough to retrieve the address of its first element.
The exact same result can be achieved by doing this (tested):
int main()
{
int array[3];
int* pArray;
pArray = &(array[0]);
}
Both methods are also valid when the accessor returns the address from a member variable of its own class.
But why, when accessing the member variable of a nested class, I'm forced to use the second method?
What are the logic stages that make it the only viable method?
But why, when accessing the member variable of a nested class, I'm forced to use the second method?
You aren't:
return current->array;
and
return &(current->array[0]);
Both do the same thing when the return type is int*. You aren't forced to use the second way.
Also, there's a bug in getArray. You don't return anything if current is null.
To be pedantic...
Apparently, the only way to do it is by returning the reference to the first element of the array in the node to which the linkedList's member variable current points to:
return &(current->array[0]);.
You're returning the address i.e. a pointer. Reference means something else.
#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.
Here's my struct:
struct node {
int load;
int tolerance;
bool has_fired;
node *in[1];
node *out[1];
};
I've tried:
node mynode;
mynode->in = null;
mynode->in = nullptr;
mynode->in = &nullptr;
mynode->in = 0;
mynode->in = false;
I really don't know what's wrong, I remember the first assignment USED to work but not anymore apparently. Any help?
EDIT: In the actual source file 'mynode' is a pointer inside of another struct.
Like this perhaps:
struct node
{
int load;
int tolerance;
bool has_fired;
node *in[1] = { nullptr };
node *out[1] = { nullptr };
};
(Note that node::in and node::out are arrays of pointers.)
Usage:
node n; // n.in and n.out are initialized
In C++11 the brace-or-equal-initializer makes the class a non-aggregate. If that's a problem, you can also omit the initializer and say:
node n;
n.in[0] = nullptr;
n.out[0] = nullptr;
Or even:
node n { 0, 0, false, { nullptr }, { nullptr } };
Try value initialization:
node mynode{};
This will value-initialize all the members, which for built-ins and PODS means zero initializaiton.
Create a constructor?
struct node
{
node()
: in{{ nullptr }}, out{{ nullptr }}
{}
...
};
This is assignment rather than initialization. Since in is an array of pointers you have to set the array element to null. Also mynode is not a pointer, so you don't use the arrow operator.
mynode.in[0] = nullptr;
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.