object's addresses.
The degenerate situation of copying a value into an object which already had
that value is less important. Just let it happen; don't always waste CPU
cycles checking for it.
--
Phlip
<-- NOT a blog!!!
Well, as long as we're dealing with hypotheticals: If (1) checking the
class for equality is cheap, (2) checking for equality frequently
evaluates to true even though it's not the same object (in the sense of
occuping the same address), and (3) using the copy constructor is very
expensive, then one can imagine using the former version, since it will
avoid unnecessary copy constructions.
The latter version ought to be the default, though.
Best regards,
Tom
That is not a declaration -- choose your words carefully.
The latter compares the ADDRESSES of two objects, while the former compares
the two objects themselves.
Yes, the former requires an accessible operator==.
Depends on a wonderous amount of factors:
(1) How the class is implemented
(2) How expensive it is to copy it
(3) How expensive it is to compare it for equality
(4) How often an object is compared to itself
If an object of the class should NEVER be assigned to itself, I would
suggest an assert:
#include <cassert>
MyClass &MyClass::opera tor=(MyClass const &rhs)
{
assert(this != &rhs);
/* Now perform assignment */
return *this;
}
--
Frederick Gotham
That is not a declaration -- choose your words carefully.
The latter compares the ADDRESSES of two objects, while the former compares
the two objects themselves.
Yes, the former requires an accessible operator==.
Depends on a wonderous amount of factors:
(1) How the class is implemented
(2) How expensive it is to copy it
(3) How expensive it is to compare it for equality
(4) How often an object is compared to itself
If an object of the class should NEVER be assigned to itself, I would
suggest an assert:
#include <cassert>
MyClass &MyClass::opera tor=(MyClass const &rhs)
{
assert(this != &rhs);
/* Now perform assignment */
return *this;
}
I think assert should not be good solution as we may not want to assert
just in case someone did it by mistake.
Here we can use shared pointers
class foo {
private:
std::tr1::share d_ptr<type_clas spt;
};
foo& foo::operator=( const foo& rhs)
{
pt.reset(new type_class(*rhs .pt)); //reset deletes the first and points
to 2nd,
//if new throws exception reset will not implement and original will
not be deleted.
return *this;
}
OR the other way
foo& foo::operator=( const foo& rhs)
{
type_class *pBefore = pt;
pt = new type_class(rhs. pt);
delete pt;
return *this;
}
These approaches are better as they are taking care of self assignment
saftey as well as exception saftey.
-SS
Well, an assert should definately not be used here but not for that
reason. Self assignment is rather common for objects when a program
gets remotely interesting. Simply not doing the assignment or devising
a way that it will just not hurt anything are the correct options.
Now, your reasoning isn't right because an assert is placed in code for
exactly that reason...in case someone accidentally violates a
pre-condition. They are there for the developer and go away in release
mode.
What you don't want is an assert that is the sole way of avoiding a
situation unless such a situation cannot be resolved, as is not the
case here. So the assert would be ok if you wanted to impose such a
restriction but the normal checks should still apply in release mode
because this could happen under conditions that where not tested and
then the program would do stupid things...and the situation is very
resolvable, you just don't do the copy.
An assert is the testing of a condition at runtime. If the condition is
true, nothing happens. If the condition is false:
(1) The program is terminated.
(2) The programmer is informed as to where they made their coding
error.
So you see, "assert" is used to catch programming errors quickly and to cut
down time on debugging.
Overkill in my opinion.
Noah Roberts posted:
If the inventor of the class deems that an object of the class should never
be assigned to itself, then an "assert" is quite appropriate. The situation
is quite akin to the following:
/* Function: CountOcc
This function counts the amount of occurrences
of a specific element in an array.
NB: (1) Neither argument may be a null pointer.
(2) The second pointer must be greater than the first.
*/
template<class T>
unsigned CountOcc(T const *pstart,T const*const pend,T const &elem)
{
assert(pstart); assert(pend); assert(pend pstart);
/* Rest of Code */
}
These asserts are very good practise in my opinion. The help the developer
without sacrificing speed of execution.
--
Frederick Gotham
If the inventor of the class deems that an object of the class should never
be assigned to itself, then an "assert" is quite appropriate. If such an inventor did indeed deem that such a pre-condition be the
case. However, that is an inappropriate precondition to enforce and
renders the class hardly usable. When designing the assignment
operator one should always be aware of, and account for (not disallow),
self-assignment. You should also try to at least provide the strong
guarantee. Both of these can often be killed with one stone simply by
accepting the parameter by value instead of by reference.
The situation The first two probably, and notice how this differs a great deal from
the self assignment problem. Namely that at least the first two
pre-conditions are totally unresolvable; there is no correct answer if
those preconditions are not met whereas the answer to self assignment
is the object itself. The last isn't even valid in that the result of
the count of any specific element in an empty array should be 0, not a
blown assert...it also guarantees nothing about the validity of that
relationship between the two addresses.
Also interesting to note is that your sticking to C constructs has
resulted in a function that is not as generic as it could be. The use
of the iterator concept instead of pointers would result in a more
useful function (it could work with any container) and remove the
necissity, and in fact the possibility, of those asserts.
The fact that asserting that a ptr != 0 in many cases is rather useless
also in that the assert can pass without a valid pointer and a 0
pointer is the easiest invalid pointer to debug. Placing the assert to
advertize the precondition is enough for it to be there though.
Why are you testing for self-assignment at all? What does the rest of
your assignment operator look like? Can you implement your operator= as
"create a temporary and swap" as in .
Gavin Deane
I would say that that depends entirely on the kind of class we're
dealing with. Let's say we have a card game, and that we have a class
called "Hand". Let's say that we code the game in such a way that a hand
should never be compared to itself -- in fact, let's say that it would be
quite perverse if it were. In such circumstances, the "assert" solves two
problems:
(1) It informs the programmer of their coding error in Debug Mode.
(2) It doesn't burdeon the valid code in Release Mode with a decrease
in speed of execution.
I believe that rule is too rigid. I don't keep many rules in mind when
programming, I like to be fluidic and open to all possibilities -- it
results in more creative code (which tends to run faster too).
If speed of execution and memory consumption are no object, then yes.
<snip code>
The first two probably, and notice how this differs a great deal from
the self assignment problem.
I believe they are very similar: They deal with something that the 3rd
party has outlawed. In the previous example, the 3rd party outlawed self-
assignment. In _this_ example, the 3rd party outlaws the passing of invalid
pointers.
Yes, but speed of execution suffers if self-assignment should trully be a
no-no. If it's extremely bizarre that an object of a certain type be
compared to itself, then we can just outlaw the practise by using an
"assert". If however it's not too weird that an object of a certain type be
compared to itself, then just go with:
if(this==&rhs)r eturn*this;
This depends on whether the 3rd party considers an empty array to be an
array.
Acknowledged, however it does guarantee that "pend" is ahead of "pstart"
(assuming of course that their comparisson doesn't invoke UB ; ) ).
I have yet to read up on iterators; can you suggest a good book? I tried
TC++PL but didn't like the way it approached the Standard Library.
Sorry I don't quite understand what you're saying in that last sentence.
--
Frederick Gotham
| last post by: |
| last post by: |
| last post by: |
| last post by: |
| last post by: |
| last post by: |
| last post by: |
| last post by: |
| last post by: |
By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use .
To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.
In C++, the assignment operator forms the backbone of many algorithms and computational processes by performing a simple operation like assigning a value to a variable. It is denoted by equal sign ( = ) and provides one of the most basic operations in any programming language that is used to assign some value to the variables in C++ or in other words, it is used to store some kind of information.
The right-hand side value will be assigned to the variable on the left-hand side. The variable and the value should be of the same data type.
The value can be a literal or another variable of the same data type.
In C++, the assignment operator can be combined into a single operator with some other operators to perform a combination of two operations in one single statement. These operators are called Compound Assignment Operators. There are 10 compound assignment operators in C++:
Lets see each of them in detail.
In C++, the addition assignment operator (+=) combines the addition operation with the variable assignment allowing you to increment the value of variable by a specified expression in a concise and efficient way.
This above expression is equivalent to the expression:
The subtraction assignment operator (-=) in C++ enables you to update the value of the variable by subtracting another value from it. This operator is especially useful when you need to perform subtraction and store the result back in the same variable.
In C++, the multiplication assignment operator (*=) is used to update the value of the variable by multiplying it with another value.
The division assignment operator divides the variable on the left by the value on the right and assigns the result to the variable on the left.
The modulus assignment operator calculates the remainder when the variable on the left is divided by the value or variable on the right and assigns the result to the variable on the left.
This operator performs a bitwise AND between the variable on the left and the value on the right and assigns the result to the variable on the left.
The bitwise OR assignment operator performs a bitwise OR between the variable on the left and the value or variable on the right and assigns the result to the variable on the left.
The bitwise XOR assignment operator performs a bitwise XOR between the variable on the left and the value or variable on the right and assigns the result to the variable on the left.
The left shift assignment operator shifts the bits of the variable on the left to left by the number of positions specified on the right and assigns the result to the variable on the left.
The right shift assignment operator shifts the bits of the variable on the left to the right by a number of positions specified on the right and assigns the result to the variable on the left.
Also, it is important to note that all of the above operators can be overloaded for custom operations with user-defined data types to perform the operations we want.
Similar reads.
main(){ Contact c( , 3); c.display(); cout << << endl; c.read(); c.display(); cout << ; ( i = 0; i < 1000000; i++){ Contact cp = c; c = cp; (!(i % 100000)) cout << ; } cout << endl; c.display(); system( ); 0; } |
=( Contact& source) { ( == &source) { * ; } { [] _pn; ( i = 0; i < 41; i++) _name[i] = source._name[i]; _pn = PhoneNumber[source._noPN]; ( i = 0; i < source._noPN; i++) _pn[i] = source._pn[i]; * ; } } |
Contact& source) { (source.isEmpty()) { setEmpty(); } { strcpy_s(_name, source._name); _name[40] = ; _pn = PhoneNumber[source._noPN]; ( i = 0; i < source._noPN; i++) _pn[i] = source._pn[i]; } } |
I made a typo, sorry. What I mean't is self-assessment. In the 2nd line of the 2nd code, the condition "this == &source" always results in false. I don't understand why this condition would result in false when the values of the variables of both objects are the same. |
Fastest entity framework extensions.
When writing a copy assignment operator, it is very important that it be able to work in the event of self-assignment. That is, it has to allow this:
Self-assignment usually doesn't happen in such an obvious way. It typically happens via a circuitous route through various code systems, where the location of the assignment simply has two Person pointers or references and has no idea that they are the same object.
Any copy assignment operator you write must be able to take this into account.
The typical way to do so is to wrap all of the assignment logic in a condition like this:
Note: It is important to think about self-assignment and ensure that your code behaves correctly when it happens. However, self-assignment is a very rare occurrence and optimizing to prevent it may actually pessimize the normal case. Since the normal case is much more common, pessimizing for self-assignment may well reduce your code efficiency (so be careful using it).
As an example, the normal technique for implementing the assignment operator is the copy and swap idiom . The normal implementation of this technique does not bother to test for self-assignment (even though self-assignment is expensive because a copy is made). The reason is that pessimization of the normal case has been shown to be much more costly (as it happens more often).
Move assignment operators must also be protected against self-assignment. However, the logic for many such operators is based on std::swap , which can handle swapping from/to the same memory just fine. So if your move assignment logic is nothing more than a series of swap operations, then you do not need self-assignment protection.
If this is not the case, you must take similar measures as above.
Get monthly updates about new articles, cheatsheets, and tricks.
Video Walkthrough
You will work on the assignments for CS107 on the myth machines, which you access remotely. You'll initially make a copy of the starter project to modify, use command-line tools to edit and debug your code, and use some 107-specific tools like Sanity Check and Submit to test and submit your work. See below for the common steps you'll use to work on assignments.
You will work on your programs in CS107 remotely on the myth machines, which are pre-installed with all the necessary development tools. Check out the getting started guide for how to log in remotely.
For each assignment, you will first "clone" a copy of the assignment starter files into your own directory so you will be able to modify files. Some assignments will have randomized or user-specific data, and each student will have their own copy of the assignment to copy. The assignments are managed using a "version control system" called git ; we will not be focusing on git in CS107, but you can feel free to look into how git works if you're interested.
Note: Do not put any CS107 assignments online publicly on GitHub or any other publicly available website . This is a violation of the Stanford Honor Code.
To clone a copy of the assignment, first navigate to the directory where you would like to store the copy of the assignment. You may wish to create a CS107 folder, for instance, in your personal AFS space, using the mkdir command. Then, use the git clone command as follows:
This will make a folder named assign0 that you can then go into to start working on the assignment. You should type the above commands exactly as shown, including the odd-looking $USER at the end, but replacing assign0 with assign1 , assign2 , etc., depending on the assignment you are cloning. Now you can start working on the assignment!
You'll use a variety of tools to work on the assignment, such as gdb (debugger) and make (compiling), that we'll introduce this quarter.
As part of each assignment, we provide a testing program called "sanity check" that ensures you have worked on certain required files, and compares the output of your program to that of the provided sample executable and reports on discrepancies, allowing you to detect and address any issues before you submit. It also allows you to add your own custom tests.
To run the sanity check tool for a given assignment with our provided tests, first navigate to the directory containing the assignment you would like to test. Then, execute the tools/sanitycheck command as follows:
In the output, if a test fails, it will indicate either "MISMATCH" or "NOT OK". MISMATCH indicates that your program successfully ran to completion but the output it produced did not match the output produced by the sample. NOT OK reports that your program did not successfully complete (exited due to a fatal error or timed out) and its output was not compared to the sample.
The default tests supplied for sanity check may not be particularly rigorous nor comprehensive, so you will want to supplement with additional tests. You can create inputs of your own and write them into custom tests to be used by the sanitycheck tool. Create a text file using this format:
To run your custom tests, invoke sanitycheck with its optional argument, which is the name of the custom test file
When invoked with an argument, sanity check will use the test cases from the named file instead of the standard ones. For each custom test listed in the file, sanity check runs the sample solution with the given command-line arguments and captures its output, then runs your program with the same arguments to capture its output, and finally compares the two results and reports any mismatches.
Once you've finished working on an assignment, it's time to submit! The tools/submit command lets you submit your work right from myth . The submit tool verifies your project's readiness for submission. It will make the project to ensure there is no build failure and will offer you the option to run sanity check. If any part of verification fails, the submission is rejected and you must fix the issues and try submit again. Here's an example of using this command.
Submission deadlines are firm. Cutting it too close runs the risk of landing on the wrong side -- don't let this happen to you! Submit early to give yourself a safety cushion and avoid the last-minute stress.
Be cautious with C: C is designed for high efficiency and unrestricted programmer control, with no emphasis on safety and little support for high-level abstractions. A C compiler won't complain about such things as uninitialized variables, narrowing conversions, or functions that fail to return a needed value. C has no runtime error support, which means no helpful messages when your code accesses an array out of bounds or dereferences an invalid pointer; such errors compile and execute with surprising results. Keep an eye out for problems that you may have previously depended on the language to detect for you.
Memory and pointers: Bugs related to memory and/or pointers can be tricky to resolve. Make sure you understand every part of your code that you write or change. Also keep in mind that the observable effects of a memory error can come at a place and time far removed from the root cause (i.e. running off the end of a array may "work fine" until you later read the contents of a supposedly unrelated variable). gdb and Valgrind can be extremely helpful in resolving these kinds of bugs. In particular, Valgrind is useful throughout the programming process, not just at the end. Valgrind reports on two types of memory issues: errors and leaks. Memory errors are toxic and should be found and fixed without delay. Memory leaks are of less concern and can be ignored early in development. Given that the wrong deallocation can wreak havoc, we recommend you write the initial code with all free() calls commented out. Much later, after having finished with the correct functionality and turning your attention to polishing, add in the free calls one at a time, run under Valgrind, and iterate until you verify complete and proper deallocation.
Use good style from the start : Always start with good decomposition, rather than adding it later. Sketch each function's role and have a rough idea of its inputs and outputs. A function should be designed to complete one well-defined task. If you can't describe the function's role in a sentence or two then maybe your function is doing too much and should be decomposed further. Commenting the function before you write the code may help you clarify your design (what the function does, what inputs it takes, and what outputs it produces, how it will be used). Start by using good variable names, rather than going through and changing them later. Using good style the first time makes your code better designed, easier to understand, and easier to debug.
Understand your code : At every step, you want to ensure that you understand the code you are writing, what it does, and how it works. Don't make changes without understanding why you are making them, and what the result will be.
Test : use our recommended testing techniques to incrementally develop your program, test at each step, and always have a working program.
Get help if you need it! : 107 has a lot of helpful resources, including written materials on the web site, textbook readings, lectures, labs, the online discussion forum, helper hours, and more. We are happy to help or answer your questions!
How can i reproduce/debug a problem that appears during sanity check.
Look through the sanity check output to find the command being executed:
Run that same command (in shell, gdb, or Valgrind) to replicate the situation being tested. You can also view the file contents (such as the hymn file in the above command) to better understand what is being tested.
Unfortunately not; custom sanity check tests compare on output only. You will need to supplement with other forms of testing to verify those additional requirements.
We strongly recommend that you resolve any sanity check failures before submitting, but the submit tool will not force you to do so. To submit a project doesn't pass sanity check, respond no when asked if you want to run sanity check, and the project will be submitted without that check.
Your gradebook page (accessible from the navigation bar at the top) lists the timestamp of the most recent submission we have received.
Although it is not necessary, if you would like to triple-check, you can view the contents of your submission by re-cloning your class repo. For example, navigate to your home directory and git clone /afs/ir/class/cs107/repos/assignN/$USER mysubmission . This will create a mysubmission directory that contains the files you submitted for assignN (be sure to replace N with the assignment number). If you're satisfied that everything is as intended in mysubmission , then you're done and you can delete the mysubmission directory. If not, figure out what's not right, fix it, and submit again.
Find centralized, trusted content and collaborate around the technologies you use most.
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Get early access and see previews of new features.
//since it will be called on r-value so why self-assignment ??
Suppose your class holds a pointer to some buffer that it allocates. Now, in a naive move-assignment operator, you would:
This will not make you dereference a null pointer, but - you've just lost all data in your buffer, which is likely not what you wanted, nor what the user expected.
There is a (narrow) exception to the rule above: The case of your move-assignment operator being 'idempotent' for self-assignment. For example, if your assignment operator only involves assignment of the members - then it's safe to self-assign just like a regular assignment (trusting that the members' self-assignment implementations are valid). Nothing will be changed or lost.
This exception to the rule is indeed narrow, since the above is mostly true for the example I gave - in which case you would use the default move-assignment operator. Still, just because you don't find this check in someone's code does not mean there's a bug.
IMAGES
VIDEO
COMMENTS
Example 2: A copy assignment operator that is written in such a way that it must check for self-assignment is probably not strongly exception-safe either. What does he mean by the term "check for self-assignment"? [INQUIRY] Dave and AndreyT shows us exactly what "check for self-assignment" means. That's good. But the question is not over.
If we have an object say a1 of type Array and if we have a line like a1 = a1 somewhere, the program results in unpredictable behavior because there is no self assignment check in the above code. To avoid the above issue, self assignment check must be there while overloading assignment operator. For example, following code does self assignment check.
If self-assignment can be handled without any extra code, don't add any extra code. But do add a comment so others will know that your assignment operator gracefully handles self-assignment: Example 1a: Fred& Fred::operator= (const Fred& f) {. // This gracefully handles self assignment. *p_ = *f.p_; return *this;
Assignment Operator General Outline. When a class contains a handle to external data, the assignment operator ( operator=) generally follows this pattern: Get rid of the old external data ( delete memory, close network socket, delete temporary file, unlock semaphore, etc.). Copy the resource from the other object to this object.
The steps in writing our own assignment operator are the following: Check for self-assignment. Delete old memory. Allocate new memory. Copy the data. Return *this. Notice the worry about self-assignment, as in "A = A". We need to check for this both to avoid unnecessary work and to avoid problems later when we delete the old memory.
In C++, assignment operator should be overloaded with self assignment check. For example, consider the following class Array and overloaded assignment operator function without self assignment check. // A sample class class Array { private: int *ptr; int size; public: Array& operator = (const Array &rhs); // constructors and other functions
I made a simple class with a int pointer created using new. i handled the assignment operator checking for self assignment and deleting the original object. after asking some questions it turns out in my example both checking for self assignment was unnecessary and deleting was unnecessary which i thought i needed to do. otherwise the pointer would move and id lose the ability to delete that ...
The first approach is more standard so if you see the second in practice it is likely a good developer will question if this is self-assignment safe or not. If you had a different structure: struct Foo {. std::shared_ptr<Bar> m_p; }; That would also be self-assignment safe if you just use m_p = src.m_p; .
I have always seen the recommendation that the check is done explicitly. You've been looking in the wrong places, see e.g. C++ Coding Standards by Sutter & Alexandrescu. Self-assignment is exceedingly rare in most programs, so an explicit check adds a small cost to every self-assignment even though the check is almost always false.
For move assignment: 1. x = std::move(y); one should have a post-condition that y has a valid but unspecified state. When &x == &y then this postcondition translates into: x has a valid but unspecified state. I.e. self move assignment does not have to be a no-op. But it should not crash.
When not to handle self-assignment. Typically the self-assignment check is skipped for copy constructors. Because the object being copy constructed is newly created, the only case where the newly created object can be equal to the object being copied is when you try to initialize a newly defined object with itself: someClass c { c };
By default, this check searches only those classes which have any pointer or C array field to avoid false positives. In case of a pointer or a C array, it's likely that self-copy assignment breaks the object if the copy assignment operator was not written with care. See also: OOP54-CPP. Gracefully handle self-copy assignment
The self-assignment check detects object identity, which C++ specifies as an. object's addresses. The degenerate situation of copying a value into an object which already had. that value is less important. Just let it happen; don't always waste CPU.
In C++, assignment operator should be overloaded with self assignment check. For example, consider the following class Array and overloaded assignment operator function without self assignment check. // A sample class class Array { private: int *ptr; int size; public: Array& operator = (const Array &rhs); // constructors and other functions
In C++, assignment operator should be overloaded with self assignment check. For example, consider the following class Array and overloaded assignment operator function without self assignment check. // A sample class class Array { private: int *ptr; int size; public: Array& operator = (const Array &rhs); // constructors and other functions
I have an overloaded assignment operator function. Within the function I have a self-assessment check that does not seem to work as expected. I've spent the whole day trying to figure out what the problem is. I am able to successfully get the self-assessment check to work properly when I write a entirely new code on my own but I am not able to ...
c++11. Move assignment operators must also be protected against self-assignment. However, the logic for many such operators is based on std::swap, which can handle swapping from/to the same memory just fine. So if your move assignment logic is nothing more than a series of swap operations, then you do not need self-assignment protection.
Usually, when overloading and assign operator, one should check for self-assignment. In a simple non-templated class it would like the following: MyClass& MyClass::operator=(const MyClass&...
To run the sanity check tool for a given assignment with our provided tests, first navigate to the directory containing the assignment you would like to test. ... Assignment Tips. Be cautious with C: C is designed for high efficiency and unrestricted programmer control, with no emphasis on safety and little support for high-level abstractions ...
There is a (narrow) exception to the rule above: The case of your move-assignment operator being 'idempotent' for self-assignment. For example, if your assignment operator only involves assignment of the members - then it's safe to self-assign just like a regular assignment (trusting that the members' self-assignment implementations are valid).