These toy examples are for helping with understanding C/C++. There is an excellent C++ samples site which demonstrates many useful things.
Last active
January 22, 2023 22:43
-
-
Save barrysteyn/9fbd5ebd0719629223f9 to your computer and use it in GitHub Desktop.
C/C++ Examples For Understanding
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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? | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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? | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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; | |
} |
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.
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
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 =)