Java-style memory management in C++ - c++

What is the best way to use Java-style references in C++? Will using shared_ptr for all classes and structs be the correct equivalent?

I highly recommend reading this answer for understanding C++ smart pointers.
Now, if by 'Java-style references' you mean you want to pass an object or struct into a method and that passed in object is not a copy of the object, but rather a reference to the object, then simply use pass by reference.
Ex:
void foo( int& ref, int val)
{
ref = ref + 1; // pass by reference
val = val + 1; // pass by value
}
...
int main()
{
int a = 10;
int b = 10;
foo(a, b);
// a is being passed by reference so foo directly modifies a
std::cout << "a = " << a << " b = " << b;
// output would be: a = 11 b = 10
}

Related

difference between variable and reference assignment

This has bothered me, I have just gotten back into c++ lately, and am well aware of references. Why does it seem there is no difference between b and c below. In other words, intuitively I would think c not being a ref variable would take a copy. It got me thinking when considering the problem of returning a reference to a local variable.
int a = 10;
int& func()
{
return a;
}
int &b = func();
int c = func(); // shouldn't this make a copy into c but c acts like a reference.
I would think c not being a ref variable would take a copy.
c is indeed a copy of a. Note that int c = func(); is copy initialization while int &b = func(); is reference initialization.
This means that if you make changes to c they will not be reflected on a. Demo
int a = 10;
int& func()
{
return a;
}
int &b = func(); //reference initialization
int c = func(); //copy initialization
int main()
{
c = 20;
std::cout << a<< " "<< b <<" "<< c <<std::endl; // 10 10 20
return 0;
}
Note also the emphasis on "initialization" instead of "assignment". These terms have different meaning in C++ unlike other languages(python for instance).
Thanks for the answers, makes sense now. This question started from "why can't I return a local variable reference to a variable if its a copy?" Well, I realized because its too late at that point - the stack is gone. I was thinking the copy could be made before the stack went away - wrong!
You can return to a reference but when you use it, segfault.
Return to a variable and, segfault immediately since it tries to copy.
int& func() // compile warning
{
int a = 10;
return a;
}
int &b = func(); // ok, but segfault if try to use b.
int c = func(); // segfault immediately

reference vs smart_ptr for dependency inversion

I have two data types, A and B and I have to store the A instance in B in order to refer the A instance in a B method. Both are instantiated in the main function, so the two variables would live for as long as the program is running.
I don't want to make copies, I want to use something like an old fashioned pointer but also I want to follow (and learn) the modern C++ best practices. So what is the most appropriate type to store the A instance in B? (and why?)
I thought that if I want to use a pointer, the best way with modern C++, is using smart pointers, but references seems easier and lighter, so what is the best practice to refer to a variable created in a scope (for example in the main function) and used in another scope (for example a method of a class that has a pointer to that variable), knowing that the scope where that variable is created lives for as long as the class exists (when the stack is deallocated, it will free both the variable and the object that has the variable reference)?
struct A {};
struct B {
A & a;
B(A & a) : a(a) {}
};
int main() {
A a{};
B b{a};
}
or
#include<memory>
struct A {};
struct B {
std::shared_ptr<A> a;
B(auto a) : a(a) {}
};
int main() {
B b{std::make_shared<A>()};
}
The program I'm making is essentially a bunch of test to learn SDL2, I published the repo here https://github.com/antcolag/prova-sdl, B is the App class and A is the EventHandler class instantiated inside the main function.
As #πάντα-ῥεῖ noticed in my particular case the only reasonable way is with smart pointer, because I'm trying to use std::thread and std::atomic, but in a most general case what is the best way to replace the old C style pointers, with a more modern approach, when a variable is allocated in the stack, used by some other object and then deallocated from the stack together with the object?
If i understood the problem, you want to move the instance to a different "owner", with A a; it is posible but it requires a memcpy() if the scope of the instance is deleted. The most easy solution is to contain it in a shared scope, that is bad because it can be a global scope, the next best thing is to pass the reference to the owner (the structure that contains the data). At the end this are cheap solutions if they are applied over and over, modern c++ has a lot of tools for memory control / flow; most of those are pointer based because the data pointer copy is trivial, note that only in combination with std::atomic or a similar lib is suitable for multithreading.
This example shows how a data pointer can be moved and used without any fancy c++, a small note on the pointer idea, in the example the pointer address is not changing as long as it is not deleted, any reference made will persist even if ref_objs order is changed, the data is "on the wild" and the pointer is a number.
#include <iostream>
struct Object {
int num = 69;
};
struct Container {
// Better to use std::vector but
// this shows better what it does
// Olso can be replaced with
// Object * ref_objs [n] if n is fixt
Object ** ref_objs;
uint32_t n_obj;
uint32_t n_obj_max;
void provision_for(uint32_t res_len){
// To initialize data is better to use
// use a method insted of the constructor;
// This alocates n spaces of obj pointers
ref_objs = new Object * [res_len];
n_obj_max = res_len;
n_obj = 0;
}
void clear_all(){
uint32_t i;
for (i=0; i < n_obj; i++){
delete ref_objs[i];
}
delete [] ref_objs;
n_obj = 0;
}
Object * add_obj(){
Object * ret = nullptr;
if (n_obj < n_obj_max){
ref_objs[n_obj] = new Object;
ret = ref_objs[n_obj];
n_obj++;
}
return ret;
}
void del_obj(uint32_t n){
if (n < n_obj - 1){
// keeps them alighned
ref_objs[n] = ref_objs[n_obj];
}
delete ref_objs[n_obj];
n_obj--;
}
int recive_obj(Object * ref){
int res = 1;
if (n_obj < n_obj_max){
ref_objs[n_obj] = ref;
n_obj++;
res = 0;
}
return res;
}
int transfer_to(Container * to, uint32_t item){
int res = 1;
if (to->recive_obj(ref_objs[item]) == 0){
if (item < n_obj - 1){
ref_objs[item] = ref_objs[n_obj - 1];
} else {
ref_objs[item] = nullptr;
}
n_obj --;
res = 0;
}
return res;
}
Object * at (uint32_t at){
return ref_objs[at];
}
Object & operator [](uint32_t at){
// [0] is added to asure the compiler that it
// is a instance and not an array
return ref_objs[at][0];
}
};
int main(void){
Container container_a;
Container container_b;
container_a.provision_for(10);
container_b.provision_for(15);
Object * x = container_a.add_obj();
Object * y = container_a.add_obj();
Object * z = container_b.add_obj();
std::cout << "container_a len -> " << container_a.n_obj << std::endl;
std::cout << "container_b len -> " << container_b.n_obj << std::endl;
y->num = 200;
container_a.transfer_to(&container_b, 0);
container_b[1].num = 400;
std::cout << "container_a obj[0].num -> " << container_a[0].num << std::endl;
std::cout << "container_b obj[0].num -> " << container_b[0].num << std::endl;
std::cout << "container_b obj[1].num -> " << container_b.ref_objs[1]->num << std::endl;
container_a.del_obj(0);
container_a.clear_all();
container_b.clear_all();
return 0;
}
(This example is template suitable, just change all Object with the typename and the instance will be Container<Object> container_a;)

Overhead of returning reference to member variable data

I am new to C++ and get confused about what goes on under the hood when a class method returns a reference to a member variable that is raw data (rather than a pointer or a reference). Here's an example:
#include <iostream>
using namespace std;
struct Dog {
int age;
};
class Wrapper {
public:
Dog myDog;
Dog& operator*() { return myDog; }
Dog* operator->() { return &myDog; }
};
int main() {
auto w = Wrapper();
// Method 1
w.myDog.age = 1;
cout << w.myDog.age << "\n";
// Method 2
(*w).age = 2;
cout << w.myDog.age << "\n";
// Method 3
w->age = 3;
cout << w.myDog.age << "\n";
}
My question is: what happens at runtime when the code reads (*w) or w-> (as in the main function)? Does it compute the address of the myDog field every time it sees (*it) or it->? Is there overhead to either of these two access methods compared to accessing myDog_ directly?
Thanks!
Technically, what you are asking is entirely system/compiler-specific. As a practicable matter, a pointer and a reference are identical in implementation.
No rational compiler is going to treat
(*x).y
and
x->y
differently. Under the covers both usually appears in assembly language as something like
y(Rn)
Where Rn is a register holding the address of x and y is the offset of y into the structure.
The problem is that C++ is built upon C which in turn is the most f*&*) *p programming language ever devised. The reference construct is a work around to C's inept method of passing parameters.

Not initialised variable after casting

Im trying to cast class, but something is wrong. I was trying static_cast<>, dynamic_cast<> but still im getting errors. I need one array with 2 types of classes.
class user
{
int value;
user(int valueInit)
{
value = valueInit;
};
int getValue()
{
return value;
}
};
class premium : public user
{
int premiumValue;
premium(int valueInt, int premiumValueInit)
{
value = valueInt;
premiumValue = premiumValueInit;
};
};
And here is main code in main() function
user fUser(10);
premium fPremium(20, 5);
premium *array = new premium[2];
(user)array[0] = u1;
array[1] = p1;
cout << "Value: " << array[0].getValue() << endl; //incorrect/random value
cout << "Value: " << array[1].getValue() << endl; //correct value
Usually I use java, so I have huge problems with c++. I know what I should do but I dont know how.
The why
The problem with your cast, (user)array[0] = u1 is that it is, theoretically, equivalent to the code below:
{
user unnamed_instance = array[0];
unnamed_instance = u1;
}
In (T)a = b; an unnamed temporary will be created having type T which is than initialized with the value of b. You are assigning to this unnamed temporary, not to a.
Note: In this case slicing takes place, ie. the value in array[0], which has type premium, will be sliced into a user.
The solution
If you'd like to treat the value in array[0] as being of type user without introducing a temporary you will need to use either pointers or references. The below will correctly assign u1 to array[0] as if array[0] was of type user.
// using a reference
static_cast<user&> (array[0]) = u1;
// using a pointer
user * ptr = static_cast<user*> (&array[0]);
*ptr = u1;

hidden g++ reference error

Compiling with GCC 4.8.1 (MinGW) with command: g++ -o test.exe test.cpp
test.cpp:
#include <iostream>
int a = 1, b = 2;
void F()
{
int &r = a;
std::cout << r;
r = b;
std::cout << r;
}
int main ( int, char** )
{
F();
F();
return 0;
}
The expected output is: 1212, but real is: 1222
It works as expected when r is defined as pointer.
void F()
{
int *r = &a;
std::cout << *r;
r = &b;
std::cout << *r;
}
Does someone have any idea where is "the key from the tent"?
In the example with a pointer:
r = &b;
This re-seats the pointer r to point to b. In the example with the reference:
r = b;
You probably think that this is analogous to the example with the pointer, but it is not. References are not re-seatable the way pointers are. Once they are initialized, they become aliases for the thing which they reference. So the line above is exactly equivalent to this:
a = b;
That is, it copies the value stored in b over to a.
The reference example is could be written like this:
void F()
{
std::cout << a;
a = b;
std::cout << a;
}
While the pointer example could be written like this:
void F()
{
std::cout << a;
std::cout << b;
}
Your "problem" is the following line:
int &r = a;
This will create a so called reference pointing to a. While references don't require additional logic when accessing them (i.e. dereferencing; compared to pointers), they still work the same way behind the scenes.
So once you hit the line
r = b;
You'll actually use the reference and update the value of a. In this case r never has it's own value. It will always point at a and essentially be an alias.
In your second example, this is different. The line
int *r = &a;
creates a pointer pointing at a and
r = &b;
will reassign that address, making the pointer now point at b.
In short, when you assign some other value (address) to a pointer, you change the pointer and it will point somewhere else. However, when assigning a new value to a reference, you're actually updating the inital value where it's referencing to, not the reference itself.
//global variables! remember that this will be like a state
//and will be freed on (data?BSS?stack?) only after end of program.
int a = 1, b = 2;
void F()
{
//You are referencing here,
//meaning, once you change the referee ( r )
//the reference will changed permanently.
//Permanently because you are referring to a global variable.
int &r = a;
std::cout << r;
//You have changed the value of ( r )
//forever!
r = b; //I think you are assuming the you have changed the reference address here?
std::cout << r;
}
void F()
{
//You have declared and initialized a pointer
//that points to global variable.
//w/c means you can also change its value forever!
int *r = &a;
std::cout << *r;
//You have changed the ( r ) address pointing to, not its value!
r = &b;
std::cout << *r;
}
Your code is absolutely fine and it's working according to your instruction.
Suppose a variable has 1000 address b variable 1004 address, now your first line is
int &r = a;
that means r has 1000 address and you did cout<< r //print 1
In second statement r = b that means 1000 address hold value of b means 2;
Now , your scenario has been changed 1000---> 2 and 1004--->2
and again you are calling F();
that's why compiler print twice 2 value. . There is a concept referencing in c++. Hope it
would be useful for u