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;
Related
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;)
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
}
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
I would like to use parameter in C++ to store back whatever value/object.
In this example, I try to store the value from the global variable as a simplified example.
This code doesn't work,
int value = 20;
void returnPointer2(int* hello)
{
hello = &value;
}
// It changes nothing
int value2 = 100;
returnPointer2(&value2);
cout << value2 << endl;
as I needed double pointer.
void returnPointer3(int** hello)
{
*hello = &value;
}
int* vp2 = new int();
*vp2 = -30;
returnPointer3(&vp2);
cout << *vp2 << endl; // expects 20
I reminded of the reference, and I can use pointer reference to get the same result.
void returnPointer4(int* & hello)
{
cout << "value : " << value;
hello = &value;
}
int* vp3 = new int();
*vp3 = -130;
returnPointer4(vp3); // also expects 20, but much simpler to use
cout << "better : " << *vp3 << endl;
I tried with double &, and it compiles.
void returnPointer5(int&& hello)
{
cout << "value : " << value;
hello = value;
}
However, it doesn't compile with the input of integer variable.
int vp4 = 123;
returnPointer5(vp4); // also expects 20, but even more simpler to use
cout << "best : " << vp4 << endl;
This is an error message.
pointer_return.cpp:31:6: error: initializing argument 1 of 'void returnPointer5(int&&)'
void returnPointer5(int&& hello)
I happened to know about move, and it works with this code.
int vp4 = 123;
returnPointer5(move(vp4)); // also expects 20, but much simpler to see
cout << "best : " << vp4 << endl;
What's the magic/logic behind this move function?
There is a lot of stuff getting mixed in here, but to keep it simple I'll address your root question.
&& is nothing at all like **.
&& is an rvalue reference, while ** is a pointer to a pointer.
As a second point, you are declaring in your function name what you want to do: returnPointer4.
You want to have a pointer to an integer returned back. int*& is the correct syntax for having a reference to a pointer.
Reading over your question again, why don't you use the following:
int& returnGlobalReference() {
return value;
}
Then in your other function:
int& value2 = returnGlobalReference();
The first attempt makes the classic mistake of passing a pointer by value, modifying its address in the function and expecting what it points to to change.
As mentioned in the comments,
void returnPointer2(int* hello)
{
hello = &value; // don't do this, it only modifies what the
// pointer hello, which resides in the stack, points to
*hello = value; // do this instead. even though hello still resides in the
// stack, you're modifying the location that hello points to,
// which was your original intention
}
why do you want to pass pointers however? is the static variable not available when you call the function? (perhaps, different files?)
The magic of std::move is:
The actual declaration for std::move is somewhat more involved, but at its heart, it's just a static_cast to an rvalue reference.
Taken from here.
As Jeffery Thomas already said, a && is not a reference to a reference, but a reference to a rvalue.
Suppose I have a class like
class Empty{
Empty(int a){ cout << a; }
}
And then I invoke it using
int main(){
Empty(2);
return 0;
}
Will this cause any memory to be allocated on the stack for the creation of an "Empty" object? Obviously, the arguments need to be pushed onto the stack, but I don't want to incur any extra overhead. Basically I am using the constructor as a static member.
The reason I want to do this is because of templates. The actual code looks like
template <int which>
class FuncName{
template <class T>
FuncName(const T &value){
if(which == 1){
// specific behavior
}else if(which == 2){
// other specific behavior
}
}
};
which allows me to write something like
int main(){
int a = 1;
FuncName<1>(a);
}
so that I get to specialize one template parameter, while not having to specify the type of T. Also, I am hoping the compiler will optimize the other branches away inside the constructor. If anyone knows if this is true or how to check, that would be greatly appreciated. I assumed also that throwing templates into the situation does not change the "empty class" problem from above, is that right?
Quoting Stroustrup:
Why is the size of an empty class not zero?
To ensure that the addresses of two different objects will be different. For the same reason, "new" always returns pointers to distinct objects. Consider:
class Empty { };
void f()
{
Empty a, b;
if (&a == &b) cout << "impossible: report error to compiler supplier";
Empty* p1 = new Empty;
Empty* p2 = new Empty;
if (p1 == p2) cout << "impossible: report error to compiler supplier";
}
There is an interesting rule that says that an empty base class need not be represented by a separate byte:
struct X : Empty {
int a;
// ...
};
void f(X* p)
{
void* p1 = p;
void* p2 = &p->a;
if (p1 == p2) cout << "nice: good optimizer";
}
This optimization is safe and can be most useful. It allows a programmer to use empty classes to represent very simple concepts without overhead. Some current compilers provide this "empty base class optimization".
It might, it might, not, depending on circumstances. If you say:
Empty e;
Empty * ep = & e;
then obviously things have to be allocated.
Try it and see. Many compilers will eliminate such temporary objects when asked to optimise their output.
If the disassembly is too complex, then create two functions with different numbers of such objects and see if there is any difference in the stack locations of objects surrounding them, something like:
void empty1 ( int x )
{
using namespace std;
int a;
Empty e1 ( x );
int b;
cout << endl;
cout << "empty1" << endl;
cout << hex << int ( &x ) << " " << dec << ( &x - &a ) << endl;
cout << hex << int ( &a ) << " " << dec << ( &a - &b ) << endl;
}
and then try running that compared with an empty8 function with eight Empties created. With g++ on x86, if you do take the address of any of the empties you get a location between x and a on the stack, hence including x in the output. You can't assume that the storage for objects will end up in the same order as they are declared in the source code.