Copy list objects value not reference - list

I'm try to create a new list object. I set the new object to an old existing object.
List<string> names = new List<string>();
names = olderList;
The problem I have is that the names list points to the olderList as a result when olderList changes, names changes too. I tried copying the values with a foreach but it's still doing the same thing, refering to the olderList.

When you make an assignment in Java, you copy the reference, not the content. Therefore, names will point to the same memory address that olderList does.
When you copy all the values, you do the same thing - you are assigning to the names list another reference to each String stored in the olderList.
An idea that might solve your problem is to use the foreach but instead of adding each element, creating a new String that is a copy of the old one. It would be something like this:
names=new List<String>();
foreach (String s: olderList) {
names.add(new String(s));
}
Check the constructor I used and its meaning at Oracle's reference site.

You must create a new list and clone every element.
If you call
olderList.clone()
it will give you a shallow copy (i.e. a new list with references to the objects of the first list). You must do something like this:
for(String name : olderList){
newList.add(name.clone());
}
reference: java api Cloneable, Object.clone()

Related

Question about List of Objects in dart Language (Flutter)

Question About List of Objects in dart (Flutter)
Hello
class Cartoon {
.
.
}
List<Cartoon> L1 = [];
….
...
List<Cartoon> L2 = [];
I define below a new list L2 containing objects from List L1 meeting some condition
List<Cartoon> L2 = [];
L2.clear();
for (Cartoon _thisObjet in L1) {
if (_thisObjet.xxx == yyyy) { //
L2.add(_thisObjet);
}
}
I check with the debugger that anytime I modify a member Value in an Object L2 , the member is is also modified in member of. original Object in List L1.
This is not expected result
In my mind I was thinking these 2 Lists should be independent ,So if someone has an explanation, I would be grateful
All variables in Dart is references to objects. The same for lists where lists only contains references to objects.
So your List<Cartoon> contains references to Cartoon objects. That means that when you look though L1 you are going though references to Cartoon objects and when you insert one of these references to the L2 list, you now have two lists containing a reference to the same object.
That also means that when you are making changes inside this object, the change can be observed when iterating though both of the lists since there are only one object.
So if you want to prevent a change to a Cartoon object to be observed in your other list, you need to make a copy of your Cartoon object and make the change on the copy. The best you can do here is to make a method on Cartoon which returns a copy of the object or make a constructor which takes a Cartoon object to create another Cartoon object.
(An important note related to this topic is immutable objects like int, String and so on (e.g. your own type of objects which only contains final fields). These type of objects cannot change their inner state but you are forced to create a new object every time you want to impose a change. By making immutable objects, you can prevent this kind of issues since any change to the object forces you to get a new object. But note, like everything, immutable is not a silver bullet to solve all problems.)

Why do sometimes you have to create a new list and sometimes you don't in Unity?

So I upgraded a project into another.
In the first project, prefabs were already in the scene, and I manually set up all the components and scripts on them.
In the second one, prefabs were created by script at runtime and I had to add everything through script.
I didn't have much trouble until I got to a script which had a public list. When the code ran it gave me a null reference everytime the list was called.
So after digging and trials and error, I found out that instead of just declaring the list (public List whatever;) I had to instantiate it (public List whatever = new List).
I'm happy I found a solution, but I don't understand it and it's bugging me. Why did I have to create a new list in the second project?
When you manually add a script to a game object in Unity editor, Unity will initialize that public List to an empty List. It will then serialize that empty List. When you instantiate a manually created prefab, it will already contain that empty List that the editor serialized.
Declaring List means that the class that you created have a List but it still does not have a value by default. In order for the List to be usable, you have to create an instance of it by assigning = new List<Data>.
its the difference between saying you have a picture(reference) or your at the place, (instance) think of it this way. lets say that list wasnt a list, it was just an int.
i can say
int i;
and i have a reference, but the reference is empty, i.e. it has no value.
but if i say
int i = 0;
it now has value, without the zero i cant act on i because the computer dosnt know what do do with it....
so basicaly saying List<Item> list;
and not List list = new List<Item>()
means you have declared that variable, and allocated space in memory, but it dosnt mean anything, until you assign a value. hope this helps.
You cannot use uninitialized variables in C#. You can initialize a variable with the default value of its type. You also can use the default value of a type to specify the default value of a method's optional argument.

allocate an std map with list pointer value in c++

I'm trying to allocate a list for each key of my std map, but using the new operator I obtain some errors (no predefined constructor is find and others), why?
My code is like this one:
std::map<QString, *std::list<ExecutionGUIObject*>> execEvtMap;
execEvtMap["t1"] = new std::list<ExecutionGUIObject*>;
*std::list<ExecutionGUIObject*>
is not a valid type and hence not a valid argument to the std::map template. You probably meant
std::list<ExecutionGUIObject*>*
which means 'pointer to list of pointers to ExecutionGUIObject objects'.
As stated by Frerich Raabe, it's a minor syntax error in your map declaration. But you gain nothing by allocating the std::list's dynamically, so why seek trouble ? Just use a map of lists.
std::map<QString, std::list<ExecutionGUIObject*>> execEvtMap;
// Creates a new (empty) list for key "t1" if one does not already exist.
void(execEvtMap["t1"]);
// Creates a new list for key "t1", or clears the existing one.
execEvtMap["t1"].clear();
// Erases a key and its list
execEvtMap.erase("t1");
If this maps owns the ExecutionGUIObject's, you'll want to tweak that too :
std::map<QString, std::list<std::unique_ptr<ExecutionGUIObject>>> execEvtMap;

c++ std::list::push_back without copying existing instance

I want to append an element to a list without copying any already existing variable.
int some_big_int = 123456789;
struct heavy_struct {
std::vector<double> vec(some_big_number, 0);
};
std::list<heavy_struct> my_list;
heavy_struc new_item;
my_list.push_back(new_item);
If I understand correctly this is what happens:
heavy_struct instance is created called new_item
my_list creates a new heavy_struct instance in which new_item is copied
Is it possible to just append a new heavy_struct, without copying already existing structure?
This copying process is heavy and useless in this case.
Yes:
my_list.emplace_back();
Will pass its arguments (none in this case) to the heavy_struct object being constructed in-place in the list.
You could use a list of pointers to your heavy struct, thus changing the heavy deep copy to a pointer asignment
std::list<heavy_struct*> my_list;
If you don't want to handle memory management either, go with shared pointers instead of raw ones.

When a `key/value` is inserted into a `std::map`, does it make its own copy of the objects?

This is inspired by an Item in Effective C# first edition, warning about overriding GetHashCode() naively.
Sorry, I do not have supporting code. By the way, this is not a homework, I am just not that familiar with C++/STL, and could not find information regarding implementation.
Suppose I create my own class named person which has 3 public mutable string fields:
First Name,
Middle Initial
Last Name
It also provides a less than operator to compare one person to another based on first name first, then middle name, and then the last name - that is all.
I create a map from person to int (say age), and fill it up with some 20 key/value pairs. I also store pointers to my keys in an array. I then change the first name of an object that say the fifth pointer points to, and try to look up a corresponding age using this modified key (remember the object is mutable and wide open).
Why did this happen?
A) Because the key used by std::map has not changed (was copied), and I changed my own copy and now my key is not found. But how can this be? I have not provided my own copy constructor. Perhaps a default one was created by the compiler?
B) The std::map collection is actually a Red-Black tree, and I happened to have a direct pointer to a key. When I have changed the key, I changed it directly in the node of a tree. Now it is likely that my node is not positioned correctly, and will not be found using a proper tree search algorithm. I should have deleted the node, then modified they key, and then re-inserted it again. If this is the case, then I suspect that STL collections in general are rather dangerous and cause noobs to make many mistakes.
C) Something else?
I would appreciate your insights.
When you use std containers all data is copied into the container. For maps this is no different.
One restriction that map places on the data is that the key is non mutable. Once it is inserted it is fixed to change the key you must find/erase and re-insert to change the value of the key.
struct Person
{
std::string first;
std::string middle;
std::string last;
Person(std::string const& f, std::string const& s, std::string const& l) { BLABLA }
bool operator<(Person const& rhs) { return BLABLABLA;}
};
std::map<Person,int> ageMap;
ageMap[Person("Tom", "Jones", "Smith")] = 68;
ageMap[Person("Tom", "I", "Smith")] = 46;
ageMap[Person("Tom", "II", "Smith")] = 24;
When you create your array of Person it will fail unless the array contains const pointers.
Person* pMap[3];
pMap[0] = &ageMap.begin().first; // Fail need a const pointer.
Person const* pMapConst[3];
pMapConst[0] = &ageMap.begin().first; // OK. Note a const pointer.
The standard container have a requirement that the class stored in them have value semantic and thus they are copied. But
if you store pointers of any kind, obviously what is pointed isn't copied;
if you try to modify the stored key (you can get a reference to it), especially playing tricks with mutable members or const_cast in order to be able to do this, in such a way than the sorting order isn't conserved, you are in UB realm.
The entries always make a copy. If the key type is std::string, then, yes, that's a copy. (Behind the scenes, std::string does some optimizations so the characters aren't necessarily always copied, but that's besides the point.)
(I think there's no way to get a pointer into the map's objects, so you can't change that key, ever again, just get copies upon iteration or other retrieval.)
Now, if your key type is *std::string (a pointer!) then the bits in the pointer are copied, but if the value of the particular string instance is later changed, then the key will effectively be changed.
(And the comparator needs to be appropriate for your key type.)
Yes -- when you insert an item into an std::map, you pass it by value, so what it contains is a copy of what you passed. Yes, the compiler will synthesize a copy constructor for you unless you declare one yourself.
It is possible to create (for example) map that uses a pointer as its key (along with a comparison function/functor that compares what the pointers refer to). If, however, you attempt to modify the keys pointed to by those pointers, you get UB. If you want to modify a key in a set/map/multiset/multimap, you need to delete the existing item from the collection, modify your copy, then insert the modified version back into the collection.