From what I know, during program startup, C++ programs initialize a memory segment for constant values.
For example if you do a cout << "Hello World!"; then the const char* argument that operator<< receives will point to that memory segment, where the string "Hello World!" is.
I was under the impression that all hardcoded literals in the code end up residing in that memory segment during runtime. However I have seen a course where the following pitfall was illustrated:
class Data
{
public:
const int& y;
Data() : y(123) {}
void f()
{
int a[10000];
for (int i = 0; i < 10000; i++)
a[i] = 50;
}
};
void main()
{
Data d;
cout << d.y << endl;
d.f();
cout << d.y << endl;
}
The pitfall was described as the situation that during the execution of the constructor for Data, instead of d.y ending up pointing to that memory segment dedicated to constant values, a behaviour similar to int temp = 123; this->y = &temp; is what actually happens, and since temp is on the stack, it will be gone in a second, and after temp is gone, f() may end up allocating a such that the address that y points to ends up included in a and thus may be overwritten when calling f().
I would like some clarifications on:
Is really what happens/can happen?
If the answer to 1. is "yes" then why does this happen? Is there some UB somewhere or something like that?
If the answer to 1. is "yes" then why was this not fixed? And by fixed I mean a solution similar to what I described above where all literals reside in their own special memory segment?
Is there anything else I should know to understand this situation better? (maybe I am not asking the right questions?)
int element;
(float)element;
cout << typeid(element).name() << endl;
Concerning:
int element;
(float)element;
cout << typeid(element).name() << endl;
int element; tells the compiler to allocated storage with sizeof (int) (and associated it with symbol element).
Additionally, it remembers the type (at compile time) for further usages of the variable (as expression).
(float)element; tells the compiler to access variable element (it's of type int) and convert its value to float (without further processing). This is a conversion of the temporary value read from element not elements storage or type. – element is still of type int.
To answer (part of) the question
Is there any way to change the type of the variable
No. It's not allowed to change the type of the variable this way.
Concerning the XY problem (suspected by molbdnilo):
It is possible to provide storage for a variable "on demand" (at runtime) using dynamic allocation with new. Though, using new directly is actually discouraged. Allocating something with new should also delete it later when memory is not needed anymore. Handling the delete correctly (double deleteing something is prohibited but not deleteing something causes a memory-leak), is not that easy to maintain.
Please, note that local variables (if not declared static or extern) have a life-time which starts not before scope is entered and ends when scope is left. Hence, it's questionable whether shared storage for alternative types is worth at all. Instead, just the respective number of alternative local variables could be used.
However, it is possible to provide a variable with possible alternative types (where only one is used at at time) with a union or a std::variant (since C++17).
A sample for std::variant:
#include <cassert>
#include <iostream>
#include <variant>
typedef std::variant<int, float> IntOrFloat;
void print(IntOrFloat value)
{
std::cout << "value: ";
if (std::holds_alternative<int>(value)) {
std::cout << std::get<int>(value) << " (int)\n";
} else if (std::holds_alternative<float>(value)) {
std::cout << std::get<float>(value) << " (float)\n";
}
}
int main()
{
IntOrFloat value = 123; // now it's an int
print(value);
value = 1.23f; // now it's a float
print(value);
return 0;
}
Output:
value: 123 (int)
value: 1.23 (float)
Live Demo on coliru
I have come across what I consider strangeness in my C++ code and am curious as to the cause. I have overloaded new for class Object and print the returned value to the console. I also print the value of this in the constructor for Object. These values do not match (they differ by one word). Is this expected?
void* Object::operator new(size_t size)
{
void* startAddress = ...
std::cout << "object starts at absolute address " << (int)startAddress << "\n";
return startAddress;
}
Object(TypeId type)
{
_type = type;
std::cout << "this is address " << (int)this << "\n";
}
Output:
object starts at absolute address 5164888
this is address 5164896
new is a raw allocator. The use of the address and amount of memory requested is implementation defined.
As an example, debug information, or information about size of block (number of objects to destroy), or (maybe? Tricky, not sure how arrays would work) vtable information can all be put before the "actual object starts".
Only trivially copiable objects are guaranteed to be copied via raw bits after this.
This means that the return value of placement new need be used, and not a reinterpreted pointer to raw storage, as an aside.
I was trying to access the private data members of the class. Everything was going fine until I came upon the int*. I don’t get what it is. I think it’s something that we can use to create a new memory address.
My code :
#include <iostream>
using namespace std;
class x
{
int a, b, c, d;
public:
x()
{
a = 100;
b = 200;
c = 300;
d = 400;
}
};
int main()
{
x ob;
int *y = (int *)&ob;
cout << *y << " " << y[1] << " " << y[2] << " " << y[3] << endl;
}
Can anyone help me in understanding it?
Its a c-style cast to access the memory occupied by the struct x as a set of ints.
It takes the address of ob, casts it from 'address of' (ie a pointer to) x into a pointer to int. The compiler happily assigns this cast to y, so you can manipulate it, or in this case, print out the memory blocks as ints. As the struct happens to be a group of ints anyway, it all works even though its a bit of a hack. I guess the original coder wanted to print out all 4 ints without having to specify each one in turn by variable name. Lazy.
Try using a cast to a char* (ie 1 byte at a time) and print those out. You'll be basically printing out the raw memory occupied by the struct.
A good C++ way would be to create an operator<< function that returns each variable formatted for output like this, then write cout << ob << endl; instead.
In the below program, tmp_data is printing first as : "Ravindra Kumar". But after copying into the map it's changed to "RRRRRRRRRRR". When we print next time, it's still printing "Ravindra Kumar" - how. It suppose to print RRRRRRRR right ?
#include <iostream>
#include <cstring>
#include <string>
#include <map>
using namespace std;
void fun_call( );
main(){
cout << "printing all data " << endl ;
fun_call();
fun_call();
}
void fun_call()
{
// static void *tmp_data;
void *tmp_data;
char *str="Ravindra Kumar";
char *str1="RRRRRRRRRRRRRRRRRRRRR";
char name[]="Ravi";
char value[100];
static std::map<std::string,void *> name_data_map;
std::map<std::string,void *>::iterator iter ;
iter=name_data_map.find(name) ;
if ( iter == name_data_map.end())
{
tmp_data = (void *) malloc ( strlen(str)+1 );
memcpy(tmp_data,str,strlen(str)+1);
name_data_map[name]=tmp_data;
cout << "Inside the if" << endl ;
}
cout << "Outside the if" << endl ;
iter=name_data_map.find(name) ;
memcpy(value,iter->second,strlen(str)+1);
cout << "value is " << value << endl ;
tmp_data=(void *)malloc(100000);
memcpy(tmp_data,str1,strlen(str1)+1);
}
output :
$ ./a.out
printing all data
Inside the if
Outside the if
value is Ravindra Kumar
Outside the if
value is Ravindra Kumar
You copy "RRRRRRRRRRRRRRRRRRRRR" into tmp_data, then exit the function, discarding tmp_data altogether (btw without freeing it, so you have a memory leak there). The next call to fun_call will create a new tmp_data local variable, whose value has no relation to what you set it before to. However, name_data_map is declared static, so it is allocated only once (on the first call to fun_call), and reused afterwards, keeping the value you put into it in the previous call (and that value is in fact a different memory block from the one you copy the R's into later).
Update - a more detailed explanation
Here
tmp_data = (void *) malloc ( strlen(str)+1 );
memcpy(tmp_data,str,strlen(str)+1);
name_data_map[name]=tmp_data;
you allocate a memory block, copy "Ravindra Kumar" into it and store a pointer to it in the map. At this point, name_data_map[name] and tmp_data point to the same memory block. Graphically it might roughly look something like this (assuming, for the sake of simplicity, that the two text literals are stored in memory consecutively, which may or may not be the case in real life):
name_data_map[name] ----
ˇ
tmp_data ---------------
ˇ
raw memory ..........Ravindra Kumar\0RRRRRRRRRRRRRRRRRRRRR\0............
If you modified the contents of that memory block (by e.g. copying a different text into tmp_data) the change would be visible through name_data_map[name] too, since both of these point to the same memory location.
However, this would not work vice versa: after changing the map value, e.g.
name_data_map[name]=str1;
the program state would look like this:
name_data_map[name] --------------------
ˇ
tmp_data ---------------
ˇ
raw memory ..........Ravindra Kumar\0RRRRRRRRRRRRRRRRRRRRR\0............
making the two pointers point to different locations, thus a change in one would not affect the other. So note that there is a fundamental difference between changing the value of a pointer, vs changing the value of the memory it points to.
You do exactly the former a few lines later, just with tmp_data:
tmp_data=(void *)malloc(100000);
memcpy(tmp_data,str1,strlen(str1)+1);
The first line changes the value of tmp_data, so now it no more points to the same place as name_data_map[name]! After that, whatever you do with the newly allocated memory block, it won't affect name_data_map[name] anymore. This is why you failed to change it.
If we declare the map as non static, than we can change it right ?
Wrong. Declaring your map static has no effect on this - it only affects the scope of your map. A nonstatic map would cease to exist when you exit from fun_call, losing all the values stored in it. While it is alive, you can change its values, regardless of it being static or not. You just need to use the right pointer for it.
If your aim was to change the value stored in the map via tmp_data, just drop the second malloc and modify the first one to allocate a longer block (as str1 is longer than str, so trying to copy str1 into a buffer having the length of str results in buffer overrun, i.e. undefined behaviour). After that, you should have a working - although nasty - code, as it is generally not a good idea to try and modify values in a map "behind its back". Moreover, mixing C constructs (malloc and raw pointers, especially void*) in C++ code is a Bad Idea. If you are only experimenting, it is acceptable - bot please don't ever do this in production code. And your intention was something different, please clarify.
Following code is simpler and seems to do what you want. Is there any reason to prefer char* over std::string as value in the map?
#include <iostream>
#include <string>
#include <map>
void fun_call()
{
const char* str="Ravindra Kumar";
const char* str1="RRRRRRRRRRRRRRRRRRRRR";
const char* name="Ravi";
static std::map<std::string,std::string> name_data_map;
std::map<std::string,std::string>::iterator iter;
iter=name_data_map.find(name) ;
if ( iter == name_data_map.end())
{
name_data_map[name]=str;
cout << "Inside the if" << endl ;
}
cout << "Outside the if" << endl ;
iter=name_data_map.find(name) ;
cout << "value is " << iter->second << endl ;
iter->second = str1;
}
main(){
cout << "printing all data " << endl ;
fun_call();
fun_call();
}
Output:
printing all data
Inside the if
Outside the if
value is Ravindra Kumar
Outside the if
value is RRRRRRRRRRRRRRRRRRRRR