+ 2

Passing Struct Which Contains Non-primitive Data Types

I understand that a struct is passed to/from a function similarly as it would be to passing primitive data types, i.e. pass-by-value. What happens if we pass a struct which was designed to contain a non-primitive datatype? struct testStruct { std::vector<int> values; }; How would this affect the values stored in the vector? testStruct func() { testStruct sample; sample.values.push_back(39); return sample; // is this valid? } int main() { testStruct obj = func(); // is this valid? }

22nd Apr 2019, 3:50 AM
Fermi
Fermi - avatar
3 Réponses
+ 2
Just to clarify, all objects in c++, whether struct, class or primitive are passed by value unless otherwise specified (by passing pointers or by using references). When an object is passed by value, a copy of it is created in memory to be used by the function. This means that the members of that object are all copied into a new object. If the member is stored as a pointer, then only the memory adress will be copied, resulting in a pointer to the same object you had before. However, if the member is being stored "raw", it will be copied outright, resulting in an entirely new copy. Let's take you example: typedef struct test { std::vector<int> values; } test; Remember, this could also be a class instead of a struct. They are passed the same way. Now, let's a define a function that modifies out values member. void modify(test t) { t.values.push_back(0); } Now, let's write a bit of code to see how these elements work together. test t; t.vec = vector<int>(); t.values.push_back(1); modify(t); cout << t.back(); // output: 1 Why does this output 1 instead of 0? When we passed "t" into modify(), it was passed by value, meaning all of the data inside of it was duplicated. Thus, when we called "t.vec.push_back(0);", we are pushing "0" into a duplicate of the real vector that we care about. When the function ends, our temporary vector is destroyed, along with the "1" that pushed into it. However, we can change this by modifying out code slightly: typedef struct test { std::vector<int>* values; } test; It's a small difference, but now we're passing vector pointers, instead of raw vector arrays. With a small modification to our code, we can fix our problem, test t; test t; t.vec = new vector<int>(); t.values->push_back(1); modify(t); cout << t->back(); // output: 0 Here, the code successfully output's 0. When the struct is copied, it copies the pointer address instead of the raw vector data. Thus, when we dereference our vector inside of the modify() function, it brin
22nd Apr 2019, 5:24 AM
Jack McCarthy
Jack McCarthy - avatar
+ 3
Jack McCarthy Thanks for the thorough explanation! If I understood correctly, variables can be modified through pointers since we are manipulating the content which is stored in the specific memory address. That said, I found that variables which are created in functions have limited lifetime, and returning a pointer to those local variables in functions often result in invalid values when accessed in main. However, char* pointers exhibit a different behaviour. Why is that so? nclude <iostream> int* func() { int test = 39; return &test; // invalid } char* func2() { char* test = "thistest"; return test; // OK } int main() { char* obj = func2(); int* obj2 = func(); std::cout << obj << '\n'; std::cout << *obj2 << '\n'; }
22nd Apr 2019, 10:10 AM
Fermi
Fermi - avatar
+ 3
Some languages have a kind of string pool where strings are stored and held for the lifetime of the program. They can be reassigned from there because their memory addresses don't change. The reason is that strings are often used more than once in programs and just keeping them in store is more performant than storing and deleting them over and over again. This applies to Python and (as it seems) also to C++. The exact implementation is dependent on the compiler and the platform: https://stackoverflow.com/questions/2327841/c-string-literal-data-type-storage
22nd Apr 2019, 5:24 PM
Thoq!
Thoq! - avatar