Skip to content

Instantly share code, notes, and snippets.

@barrysteyn
Last active January 22, 2023 22:43
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 9 You must be signed in to fork a gist
  • Save barrysteyn/9fbd5ebd0719629223f9 to your computer and use it in GitHub Desktop.
Save barrysteyn/9fbd5ebd0719629223f9 to your computer and use it in GitHub Desktop.
C/C++ Examples For Understanding

Introduction

These toy examples are for helping with understanding C/C++. There is an excellent C++ samples site which demonstrates many useful things.

#include <stdio.h>
#include <stdlib.h>
void func(int* b) {
b = (int*)malloc(sizeof(int)); //What is malloc? Why can't I use new? What's the difference
*b = 400;
printf("%d\n", *b); //What will print here
}
int main() {
int* a = 0;
func(a);
printf("%d\n", *a); //Error - but why? Also, is there a memory leak?
}
//This example follows on from example1.c
#include <stdio.h>
#include <stdlib.h>
void func(int **b) {
*b = (int*)malloc(sizeof(int));
**b = 400;
printf("%d\n", **b); //What will print here
}
int main() {
int **a = (int**)malloc(sizeof(int*));
func(a);
printf("%d\n", **a); //Why does this work?
}
//Ahhhh sanity! This example follows from example 1 and example 2.
//Notice how much neater it is
#include <iostream>
using namespace std;
void func(int*& b) {
b = new int;
*b = 400;
}
int main() {
int * a;
func(a);
cout << *a << endl; //Why does this work?
}
//Constructors and destructors without move constructor
#include <iostream>
using namespace std;
class X {
private:
int num;
public:
//Default constructor
X() : num(0) {
cout << "Default Constructor" << endl;
}
//Overloaded constructor
X(const int& val) : num(val) {
cout << "Overloaded Constructor: Setting num to " << val << endl;
}
//Copy constructor
X(const X& lVal) {
this->num = lVal.num;
cout << "Copy Constructor" << endl;
}
//Copy assignment constructor
X& operator=(const X& lVal) {
this->num = lVal.num;
cout << "Copy Assignment Operator"<<endl;
return *this;
}
//Destructor
~X() {
cout << "Destructor"<<endl;
}
};
X doSomething() {
X x(100);
return x;
}
int main() {
cout << "x1:"<<endl;
X x1 = doSomething();
cout << "x2:"<<endl;
X x2;
x2 = doSomething();
}
// Rule of 5 and Move constructor example
// We will use char* here on purpose (instead of say string)
// Also, this example DRYs the code as much as possible. Can you spot where?
#include <iostream>
using namespace std;
class X {
private:
int test;
char* str;
public:
//Default constructor
X() : str(NULL) { cout << "Default Constructor" << endl; }
//Copy constructor
X(const X& lVal) : X(lVal.str) { cout << "Copy Constructor" <<endl; }
//This is the copy assignment operator
X& operator=(const X& lVal) { cout << "Copy assignment operator" << endl; return *this = lVal.str; }
//Destructor
~X() { cout << "Destructor" << endl; if (str) delete[] str; }
//Move constructor
X(X&& rVal) {
cout << "Move constructor" << endl;
this->str = rVal.str; //Shallow copy
rVal.str = NULL; //Important - set to null otherwise rVal destructor will destroy heap
}
//----- Rule Of "5" Ends Here -----//
//Overloaded constructor
X(const char* lVal) : X() {
cout << "Overloaded constructor: X(const char* lVal)" << endl;
*this = lVal;
}
//Assignment operator (Note: This is not the copy assignment operator)
X& operator=(const char* str) {
cout << "Assignment operator overloaded operator=(const char* str) " << str << endl;
if (this->str) delete [] this->str;
this->str = new char(strlen(str));
for(int i=0; str[i]; this->str[i] = str[i], i++); //Deepcopy - done explicitly here as an example to contrast from shallow copy in move constructor
return *this;
}
const char* getStr() const { return this->str; }
};
X retByVal() {
return X("Hello World");
}
int main() {
X x4(retByVal());
return 0;
}
@rodrigoruiz
Copy link

Could you give me a practical example of when the copy constructor and assignment constructor should be different? I've never seen those in a higher level language, and never missed it =)

@barrysteyn
Copy link
Author

There is no such thing as an assignment constructor (that is my fault because I called it that, but it is incorrect). Instead, what we are talking about is a copy constructor and an overloaded assignment operator. I assume you are asking what is the difference and when would we use them. Here is a more practical example using c++ stl strings:

string s1,                        //normal default constructor
          s2("Hello World") //an overloaded constructor that takes a string as input
          s3(s1)                  //the copy constructor: You are "constructing" s3 as a copy of s1
          s4 = s1;               //also the copy constructor because the = is being used during obj declaration

s1 = s2; //this is the overloaded operator =. we are not constructing anything here, instead, we are just copying the data from s2 into s1

Hope the above clears things up a bit.

@rodrigoruiz
Copy link

But what is the practical different between "s1 = s2" and "s4 = s1"?
To me they basically do the same thing, copy content from one string to another.
Why do I even need to know that underneath there are two different methods being called?
Is there any reason to actually implement those two methods in different ways?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment