Let's say I allocate memory to a pointer to a structure:
CatStructure * cat; // assume a CatStructure has name and weight
Let's say I initialize cat to:
cat->name = "pippy";
cat->weight = 100;
If I save a reference to cat->name and cat->weight, do I still need to save a reference to cat? In other words, is it necessary to save a reference to a pointer to a structure if I've already saved references to its members?
CatStructure *cat; does not allocate memory for the given struct, it just gives you a place to store a reference to a pointer. We'll say that you know this, and that you're newing correctly to actually allocate memory.
Every new must be matched with a corresponding call to delete or you will leak memory. Technically if you're saving a reference to one of the members correctly you could do some pointer math to recover the reference to the struct, but that's unnecessarily obtuse. Just save the pointer so you can clean it up later.
if you delete the structure, any references to its pointers or members will no longer be valid. those invalid pointers/references are called 'dangling'.
Related
I'm going through this Rust tutorial - https://doc.rust-lang.org/book/ch02-00-guessing-game-tutorial.html - and came across this block of code:
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
My confusion is why we need to pass a reference to the guess variable, as opposed to just the variable itself. Is there a reason it was designed this way?
In my understanding, guess is a pointer which holds a memory address. Then, if guess is dereferenced like so *guess, this will return the value at the memory address where the String is held.
So, it seems like the read_line function would only need the address of the String to read to. Ie, called like: read_line(guess) (or read_line(mut guess)).
I'm confused why this isn't possible, and why read_line is defined to take the reference to a String, which is the address of a 'pointer' (?) as opposed to just the String (pointer) itself.
Values of type String own the memory holding the characters — they do contain a pointer to heap memory, and when they are dropped, they deallocate that memory.
If you pass a String to a function, you're moving the String and thereby transferring ownership of that memory. Then, at the end of the function, the String and its memory will be discarded unless the function returns the String value back to the caller:
fn moving_read_line(self, string: String) -> std::io::Result<(String, usize)> { ... }
This is less convenient and less flexible (for the caller) than accepting a mutable reference, which does not transfer ownership, only “borrows” it.
The variable guess is actually not a pointer, but a struct that contains a pointer to some memory, as well as the size of that allocated memory. If you dereference a String, you will get a slice, which has a pointer to the underlying memory, as well as the size of the window into that memory, but that pointer and size cannot be modified. The slice is not the owner of the memory being referenced. In order to modify the size or allocate new underlying memory for String, you need a reference to the String, hence the need for the mut reference
Let's consider a complex structure in fortran
TYPE ComplexStrType
! Static as well as dynamic memory defined here.
END TYPE ComplexStrType
Defined a physical space (allocated on the stack memory I think) to use two variables of ComplexStrType:
TYPE(ComplexStrType) :: SomeComplexStr
TYPE(ComplexStrType) :: AnotherComplexStr
TYPE(ComplexStrType),POINTER :: PointerComplexStr
Then, I use SomeComplexStr to define a few stuff in the stack and to allocate a big space in the dynamic memory.
Now, suppose I want to point AnotherComplexStr to SomeComplexStr and forget space I have defined in the stack memory to AnotherComplexStr. To do that I use a simple but useful trick which converts some variable in a Target:
FUNCTION TargComplexStr(x)
IMPLICIT NONE
TYPE(ComplexStrType),INTENT(IN),TARGET :: x
TYPE(ComplexStrType),POINTER :: TargComplexStr
TargComplexStr => x
END FUNCTION TargComplexStr
And then I point PointerComplexStr to SomeComplexStr:
PointerComplexStr => TargComplexStr(SomeComplexStr)
Finally, I do AnotherComplexStr equal to PointerComplexStr:
AnotherComplexStr = PointerComplexStr
After that, it's supposed SomeComplexStr as well AnotherComplexStr are pointing to the same static and dynamic memory.
The thing is:
How can I free the space used by AnotherComplexStr used when I defined it at the beggining?
How do you recomend me nullify the pointers?
Is that practice safe, or do I have to expect some strange memory leaks on the execution?
If it's possible, how can I point the "pointed variable" to its original form? (Just in case I have to use it again as normal variable)
NOTE: It's useful because at the execution we can be decided if we want to use AnotherComplexStr as what it is, a complex and allocated structure, or we can switch it to be treated as a pointer and points it to another thing which already has the information we need. If there is another and easy way to do that, please tell me.
The "trick" that you are using in TargComplexStr does not work the way you think - that function offers nothing useful over simple pointer assignment.
You can associate a non-TARGET actual argument with a TARGET dummy argument, as you are doing, but when the procedure with the TARGET dummy argument completes, any pointers that were associated with the dummy argument become undefined (F2008 12.5.2.4 p11).
(Pointers can only be associated with targets, therefore something that isn't a target cannot have a pointer associated with it.)
This means that the result of the function is a pointer with undefined association status. It is not permitted to return a pointer with undefined association status from a function (F2008 12.6.2.2 p4).
The pointer assignment statement would then make PointerComplexStr become an undefined pointer. PointerComplexStr is then referenced in the assignment to AnotherComplexStr. It is not permitted to reference a pointer with undefined association status (F2008 16.5.2.8 p1).
Intrinsic assignment creates a copy of a value. This is the case even if the object on the right is a pointer - a copy of the value of the target of that pointer is created. Intrinsic assignment does not, at the level of the top data object being assigned[1], make one variable reference the storage of another. As far as I can tell, the intent of your entire example code could be replaced by:
AnotherComplexStr = ComplexStr
If you are trying to do something different to that, then you need to explain what it is that you are trying to do.
[1]: If the type of an object being assigned is a derived type that has a pointer components, then the definition of the value of the object includes the pointer association status of the pointer component, but not the value of the target of the component itself (F2008 4.5.8).
I have a function that takes a borrowed HashMap and I need to access values by keys. Why are the keys and values taken by reference, and not by value?
My simplified code:
fn print_found_so(ids: &Vec<i32>, file_ids: &HashMap<u16, String>) {
for pos in ids {
let whatever: u16 = *pos as u16;
let last_string: &String = file_ids.get(&whatever).unwrap();
println!("found: {:?}", last_string);
}
}
Why do I have to specify the key as a reference, i.e., file_ids.get(&whatever).unwrap() instead of file_ids.get(whatever).unwrap()?
As I understand it, the last_string has to be of type &String, meaning a borrowed string, because the owning collection is borrowed. Is that right?
Similar to the above point, am I correct in assuming pos is of type &u16 because it takes borrowed values from ids?
Think about the semantics of passing parameters as references or as values:
As reference: no ownership transfer. The called function merely borrows the parameter.
As value: the called function takes ownership of the parameter and may not be used by the caller anymore.
Since the function HashMap::get does not need ownership of the key to find an element, the less restrictive passing method was chosen: by reference.
Also, it does not return the value of the element, only a reference. If it returned the value, the value inside the HashMap would no longer be owned by the HashMap and thus be inaccessible in the future.
TL;DR: Rust is not Java.
Rust may have high-level constructs, and data-structures, but it is at heart a low-level language, as illustrated by one of its guiding principle: You don't pay for what you don't use.
As a result, the language and its libraries will as much as possible attempt to eliminate any cost that is superfluous, such as allocating memory needlessly.
Case 1: Taking the key by value.
If the key is a String, this means allocating (and deallocating) memory for each and every look-up, when you could use a local buffer that is only allocated once and for all.
Case 2: Returning by value.
Returning by value means that either:
you remove the entry from the container to give it to the user
you copy the entry in the container to give it to the user
The latter is obviously inefficient (copy means allocation), the former means that if the user wants the value back in another insertion has to take place again, which means look-up etc... and is also inefficient.
In short, returning by value is inefficient in this case.
Rust, therefore, takes the most logical choice as far as efficiency is concerned and passes and returns by value whenever practical.
While it seems unhelpful when the key is a u16, think about how it would work with a more complex key such as a String.
In that case taking the key by value would often mean having to allocate and initialise a new String for each lookup, which would be expensive.
I have a C++ dll with the following method:
//C++ dll method (external)
GetServerInterface(ServerInterface* ppIF /*[OUT]*/)
{
//The method will set ppIF
}
//ServerInterface is defined as:
typedef void * ServerInterface;
To access the dll from a C# project, I created a C++/CLI project and declared a managed class as follows:
public ref class ComWrapperManager
{
//
//
ServerInterface _serverInterface;
void Connect();
//
//
}
I use the Connect() method to call GetServerInterface as shown below. The first call works, the second doesn't. Can someone explain why? I need to persist that pointer as a member variable in the managed class. Any better way to do this?
void Connect()
{
ServerInterface localServerInterface;
GetServerInterface(&localServerInterface); //THIS WORKS
GetServerInterface(&_serverInterface); //THIS DOESNT
//Error 1 error C2664: 'ServerInterface ' :
//cannot convert parameter 1 from //'cli::interior_ptr<Type>'
//to 'ServerInterface *'
}
You are passing a pointer to a member of a managed object. Such pointers are special, known as interior pointers. They are tracked by the garbage collector, it will modify the pointer value when the managed object is moved when the GC compacts the heap.
Problem is, you are passing that pointer to unmanaged code. The GC is not capable of modifying the copy of the pointer value that the native code is using. Now disaster strikes when another thread triggers a garbage collection, just when the native code is executing and dereferences the pointer. The object no longer exists at the original address. Very, very bad. And extremely hard to diagnose since it is so unlikely to happen.
The compiler can see you making this mistake. And complains with C2664.
The workaround is to pass a pointer that's stored in a memory location that's not going to get moved by the GC. Such a location is very easy to come by, a local variable qualifies. It is stored on the stack, it isn't going to be moved. So make it look like this instead:
void Connect()
{
ServerInterface temp;
GetServerInterface(&temp);
this->_serverInterface = temp;
// etc..
}
Which you already discovered yourself, just don't forget to assign the class member.
Here's why you can't do the second one: _serverInterface is a void pointer that is part of a managed class. Think about what the garbage collector does... It's allowed to move the managed objects around in memory however it wants, so the address of the void pointer can change from moment to moment. Therefore, it's not valid to use that address.
There are two solutions to this:
As you noted, where you can pass the address of a stack variable to the unmanaged method. Unlike managed objects, the stack doesn't move when the garbage collector does its thing, so the address doesn't change. You can then take the data stored in the stack variable and copy it to the class field, and that works fine, because you're not dealing with the address of it.
As the other answerer noted, you can lock your managed object in memory. Once it can't move, you can take the address of the void pointer field without issue. (He's showing C# syntax where you're looking for C++/CLI syntax. I'm not at a compiler to check, but I believe that the C++/CLI syntax is not the same.)
Of the two solutions, I prefer #1, the one you already have implemented: Solution #2 introduces a block of unmovable memory in the middle of the space that the garbage collector wants to rearrange. Given a choice, I prefer not to hamstring the garbage collector.
Hopefully this isn't too stupid but I want to make sure I'm doing this right.
Some Qt functions return Qt objects as values, but we may want to store them in a pointer somewhere. For example, in QDomDocument, the function documentElement returns a QDomElement, not a pointer to it. Now, as a member of my class I have:
QDomElement *listRootElement;
In a function that sets things up I am using this:
listRootElement = new QDomElement;
*listRootElement = mainIndex->documentElement();
(mainIndex is a QDomDocument.)
This seems to work, but I just want to make sure I'm doing it right and that nothing will come back to bite me.
It would be very similar for some of the image functions where a QPixmap might be returned, and I want to maintain pointers to QPixMap's.
Thanks for any comments!
Assuming that you want to store a pointer to a QDomElement for some reason, and assuming that you aware of the potential pitfalls with pointers (like, two pointers might point to the same object):
The only thing to keep in mind is that the popular 'parent takes care of deleting children' system which Qt uses is only available for QObject (sub-)classes. So when new'ing a QString or a QDomElement or something like that, keep in mind that you do have to delete it yourself, too.
I'm guessing, but I think this:
listRootElement = new QDomElement(mainIndex->documentElement());
...may allow the compiler to optimise better (see this question for some reasoning).
You're overwriting the initially allocated object:
QDomElement *listRootElement; // undefined ptr value, I'd prefer null or new right away
listRootElement = new QDomElement;
*listRootElement = mainIndex->documentElement();
You're essentially doing:
int *x = new int(42);
*x = 47;
This works because both QDomElement and int implements the assignment operator (=).
Note that there's no need to delete anything, as the returned temporary is copied into your newly allocated object.