I would like to understand the
purpose of the Duplicate() function
when used on a variable before it's
returned by a function. It would be nice if you
could provide an example of when the
use of Duplicate() is important or
necessary.
Does it have other purposes?
I have heard others mention Duplicate() in the context of data integrity, and I would like to get a better understanding of how it works and when to use it.
I often see this:
<cfreturn Duplicate(local.myVariable)>
When this also returns the same result:
<cfreturn local.myVariable>
While most variables are passed by value in ColdFusion, Structures are not -- they are passed by reference, which can cause unintentional overwriting of values, if you aren't careful.
Using Duplicate() creates an identical copy of the variable in another location in memory, so that when it is passed by reference (note that you are still passing by reference, there is no way to force a pass by value) any changes made to the data from the caller do not affect the source of the return.
Duplicate is used for passing variables by value than reference .
Structures in ColdFusion are usually passed by refrence if you use
cfset struct1 = struct2
To avoid changes in struct1 while updating struct2, we use
cfset struct1 = duplicate(struct2)
Related
I made the following method in a C++/CLI project:
void GetSessionData(CDROM_TOC_SESSION_DATA& data)
{
auto state = CDROM_TOC_SESSION_DATA{};
// ...
data = state;
}
Then I use it like this in another method:
CDROM_TOC_SESSION_DATA data;
GetSessionData(data);
// do something with data
It does work, returned data is not garbage, however there's something I don't understand.
Question:
C++ is supposed to clean up state when it has exitted its scope, so data is a copy of state, correct ?
And in what exactly it is different from the following you see on many examples:
CDROM_TOC_SESSION_DATA data;
GetSessionData(&data); // signature should be GetSession(CDROM_TOC_SESSION_DATA *data)
Which one makes more sense to use or is the right way ?
Reference:
CDROM_TOC_SESSION_DATA
Using a reference vs a pointer for an out parameter is really more of a matter of style. Both function equally well, but some people feel that the explicit & when calling a function makes it more clear that the function may modify the parameter it was passed.
i.e.
doAThing(someObject);
// It's not clear that doAThing accepts a reference and
// therefore may modify someObject
vs
doAThing(&someObject);
// It's clear that doAThing accepts a pointer and it's
// therefore possible for it to modify someOjbect
Note that 99% of the time the correct way to return a class/struct type is to just return it. i.e.:
MyType getObject()
{
MyType object{};
// ...
return object;
}
Called as
auto obj = getObject();
In the specific case of CDROM_TOC_SESSION_DATA it likely makes sense to use an out parameter, since the class contains a flexible array member. That means that the parameter is almost certainly a reference/pointer to the beginning of some memory buffer that's larger than sizeof(CDROM_TOC_SESSION_DATA), and so must be handled in a somewhat peculiar way.
C++ is supposed to clean up state when it has exitted its scope, so
data is a copy of state, correct ?
In the first example, the statement
data = state
presumably copies the value of state into local variable data, which is a reference to the same object that is identified by data in the caller's scope (because those are the chosen names -- they don't have to match). I say "presumably" because in principle, an overridden assignment operator could do something else entirely. In any library you would actually want to use, you can assume that the assignment operator does something sensible, but it may be important to know the details, so you should check.
The lifetimes of local variables data and state end when the method exits. They will be cleaned up at that point, and no attempt may be made to access them thereafter. None of that affects the caller's data object.
And in what exactly it is different from the following you see on many
examples:
CDROM_TOC_SESSION_DATA data;
GetSessionData(&data);
Not much. Here the caller passes a pointer instead of a reference. GetSessionData must be declared appropriately for that, and its implementation must explicitly dereference the pointer to access the caller's data object, but the general idea is the same for most intents and purposes. Pointer and reference are similar mechanisms for indirect access.
Which one makes more sense to use or is the right way ?
It depends. Passing a reference is generally a bit more idiomatic in C++, and it has the advantage that the method does not have to worry about receiving a null or invalid pointer. On the other hand, passing a pointer is necessary if the function has C linkage, or if you need to accommodate the possibility of receiving a null pointer.
The declaration of sqlite3_exec is using a non-const pointer to non-const sqlite3 object
sqlite3_exec( sqlite3* db, const char* command, ... )
This is reasonable, since the function will need a pointer to traverse the database and the data within can be modified by the command passed to sqlite3_exec.
However, is it save to assume, that sqlite3_exec does always return with the sqlite3* db storing the same address as before? Even if errors occur?
The reason why this question arises, is because I try to write a C++ wrapper, using RAII (most likely following the rule of zero). The most natural way to represent the pointer to the database is therefore a std::unique_ptr. Obviously I cannot pass it directly to sqlite3_exec, but I could do this:
sqlite3_exec( myUniquePointer.get(), ... );
Alternatively one could release the pointer and transfer the ownership back to the unique_ptr, but this is less elegant. So the way via get() would be preferred, but therefore the pointer would not be allowed to have a different state after the execution, because the unique_ptr could not track it and would point to an inappropriate address.
You're confused about the way the language works. It is not possible for a function that takes a pointer-to-anything argument to modify the pointer itself.
No matter what sqlite3_exec does, therefore, the value of db in the caller (the "address") will be unchanged.
(The functions sqlite3_close and sqlite3_close_v2 will invalidate the database pointer, by deallocating the memory that it points to, but even then, the bit representation of the pointer is unchanged and it's possible for a correct program to observe that fact.)
I'm developing a class that, among other things, will create a block of memory and perform some processing on this memory. The user will do something like this:
MyClass m;
float* data = m.createData();
/* user writes to `data` ... */
m.processData();
Keep in mind that createData() will be called only once, MyClass keeps an internal pointer to data, and all processData() calls will always act on this data.
My question is about the signature of the processData() method. I'm a bit uncomfortable with the fact that processData() implicitly modifies data. Should I require data to be passed as a parameter (even being redundant) just to make this behavior explicit to the user?
MyClass m;
float* data = m.createData();
/* user writes to `data` ... */
m.processData(data);
I'm a bit uncomfortable with the fact that processData() implicitly modifies data.
Actually, processData doesn't modify data at all. Given your description, it modifies the object that data points to. But only because the internal pointer happens to point to the same object.
Should I require data to be passed as a parameter (even being redundant) just to make this behavior explicit to the user?
If you intend to use the internal pointer anyway, then definitely not. Requiring user to pass an argument that's not used would be very confusing.
If you intend to use the passed pointer instead, then it would not make much sense to store the pointer within the class.
user needs to access this data (write and read).
The object oriented approach is to not return the pointer to the data, but instead write member functions to MyClass that perform the writing and reading.
A non-object-oriented approach is fine as well: Replace createData and processData with free functions, return a std::unque_ptr<float[]> (or better yet, use std::vector) to the data, and get rid of MyClass entirely.
No, you should not.
Your function createData() returns a pointer. This implies, that the data to which the pointer points might be modified.
If you want to pass a copy of your data to the user, don't pass a pointer (but it sounds like you don`t want that).
processData() is a member function of your MyClass - as long as it is not marked const you don't give any guarantees that you don't modify the internal data.
The only point where i would watch out is, if you want to invalidate the pointer you passed to the user. Then you should explicitly tell about this in your documentation or even switch to some kind of smart pointer.
If this approach seems to unsafe for you, it might be a better way to not return a pointer, but instead provide member functions to do the read/write access. This gives you full control about how and when the user changes your data, e.g. for thread-safety.
I have noticed that most C++ experts always advice it's better to pass by value, due to RVO. This allows me not worry too much about pointer manipulation and is easier to write code as well. No complaints there. This makes me wonder whether it is the correct approach to not use dynamic memory allocation (on the heap) at all and always pass parameters and return results by value?
This means instead of coming up with signatures like this:
Character* getCharacter(Sprite *sprite, Action* action)
I should more or less stick to signatures like:
Character getCharacter(Sprite sprite, Action action)
Is my understanding correct? or did I juth think i thaw a putthy cath?
They each have there pro's and con's. remember that using words like "always" is an absolute. Only the Dark Side deals in absolutes.
So let's look at each way and when we would use them.
Pass by value is good when the object being passed is smaller (since a local copy gets made). It is also good if you want to be sure to not accidentally change the original data. Its shortcoming is it makes a local copy and that can be bad if it is really big.
Pass by reference only passes a memory address. Therefore, large objects can be passed for a relatively low footprint. Also, with a reference, you can modify the original (this is both good and bad). This enables you to "return" more than one variable (so to speak). So obviously, the big con here is that you can mistakenly change the original data.
Constant pass by reference is generally accepted to be a very strong candidate for doing things. It has the pros of both pass by reference and value. Low footprint since it is a reference AND you can't change the original. There aren't many cons accept for the fact that your use of the variable in the method needs to change a little. Remember, its a const and therefore cannot be modified in the function.
Remember, there is no magic-bullet. Nothing is always better. Determine what you need and select the right tool for the job.
EDIT: also, has been said. Passing is not the same as dynamic allocation. dynamic allocation only happens with the "new" keyword. My suggestion would be to avoid the "new" keyword for now until you have a better understanding of arguments and pointers.
Whether or not you allocate an object on the heap typically is driven by one of the following concerns:
If the new object needs to outlive the function that creates it, the object must be allocated on the heap.
If the object is very large, and does not fit on the stack, then you must allocate it on the heap.
Beyond that, the choice of pass by value or pass by reference is determined by the semantics. If you want to operate on a copy, pass by value. If you want to operate on the actual object, pass by reference.
Your statement is simply utterly untrue. There is some light advice to pass by value instead of the mainstream const-ref in the special case where the function will copy the argument to a local variable anyway.
And for passing by-nonconst-pointer, pass by value was never an alternative. The first implies an optional out or inout param and the second and input param.
And mentioned dynamic allocation in question title just fits no way with the content.
Your understanding in definitely not correct.
let's say I want my users to use only one class, say SpecialData.
Now, this data class would have many methods, and depending on the type of data, the methods do different things, internally, but return externally similar results. Therefore my wanting to have one "public" class and other "private", child classes that would change the behavior of methods, etc...
It would be amazingly more simple for some types of data that need to be built to do something like this:
SpecialData& sm = SpecialData::new_supermatrix();
and new_supermatrix() would return a SuperMatrix instance, which inherits from most behaviors of SpecialData.
my header:
static SpecialData& new_supermatrix();
my cpp:
SpecialData& SpecialData::new_supermatrix()(){
return SuperMatrix(MATRIX_DEFAULT_MAGNITUDE,1000,1239,FLOAT32,etc...);
}
The problem is, I get this error, which is probably logical due to the circumstances:
invalid initialization of non-const reference of type ‘SpecialData&’ from a temporary of type ‘SpecialData’
So, any ideas?
Well, you've got three choices:
a) You want to have only one instance of SuperMatrix anyway. Then go for the static function member route as has already been suggested.
b) You want to create multiple instances. Then you have to return a pointer instead of references and create the objects with with new (i.e. return new SuperMatrix(...).
c) As an alternative to option b, you can also return merely an object, i.e.
SpecialData SpecialData::new_supermatrix()(){
return SuperMatrix(MATRIX_DEFAULT_MAGNITUDE,1000,1239,FLOAT32,etc...);
}
However, this requires a (deep-)copy operator (the default one won't suffice more often than not), and it means that the object is created on the stack, then copied and that copy is being returned. The good thing is, this won't leak memory if you don't actually receive the result into a variable. The bad thing is, if the object is very large, this can be very memory- and time-consuming.
Whatever you are going to do with it, these solutions are mutually exclusive, both technically and logically. ;)
Simple answer - you can't use references like that. Your new_supermatrix function returns a nameless temporary value which you try to bind to a non-const reference - C++ only allows such values to be bound to const references. If you want to write functions like this, you need to make them return a pointer to a dynamically allocated object, or stick with returning a value, but assign the return value to another value in the calling code.
This code has several problems. First of all, you probably want to use pointers here instead of references. Returning a reference to an object created on the stack like you do in your new_supermatrix will lead to a crash almost immediately. It needs to be allocated with new and passed back as a pointer if that's what you want but I'm not exactly sure what you're trying to do. But anyway, this is what's causing your error, you're returning a reference to a temporary variable.
You need to actually use the new operator. The creation you get by return SuperMatrix(MATRIX_DEFAULT_MAGNITUDE,1000,1239,FLOAT32,etc...); allocates the object on the stack, which is cleaned up when the function returns (which it is doing in the same line). Using new causes it to be allocated on the heap.
In your method, you can use a static:
SpecialData& SpecialData::new_supermatrix()(){
static SuperMatrix supermatrix(MATRIX_DEFAULT_MAGNITUDE,1000,1239,FLOAT32,etc...);
return supermatrix;
}
You must not return a reference to a temporary/local object.
This and many other common errors-to-be-avoided are explained in Meyers' book, Effective C++.
You're returning a reference to a temporary object, which is bad news, since once your method exits, the object doesn't exist anymore.
Read up on creational design patterns. The one that looks closest to what you want to do is the Factory Method pattern.