Thread: /= doesn't do what you think it does?

  1. #1
    Registered User
    Join Date
    Jun 2008
    Posts
    106

    /= doesn't do what you think it does?

    It will make sense once you're done reading...

    Code:
    for ( ...k++)
    for (int i = 0; i <= argc-3; i++){			
    	cout << kFmap[k][namesmap[i]] << " kFmap | ";
    	cout << F[kFmap[k][namesmap[i]]] << " | ";
    	F[kFmap[k][namesmap[i]]] /= argc-2;
    	cout << F[kFmap[k][namesmap[i]]];
    	cout << endl;
    }
    I would have something like this as result:

    F(before /=) probability(Fafter /=)
    1 0.10
    1 0.10
    1 0.10
    3 0.30
    1 0.10
    1 0.10
    3 0.03 --> It took the value above, 0.3, and divided it by the total
    1 0.10
    1 0.10
    1 0.10

    ..so it took the probability twice on the second value that was the same as a value already calculated! Whats the deal with this? Logically, F[kFmap[k][namesmap[i]]] /= argc-2, should replace the current value of each F value with the divided by (argc-2) value of the current F. Why is it doing dividing the the n-1 value of F for the calculation of F(n). This behavior seems to be recursive as I get multiple divisions for multiple similar values. Removing the identical occuring values is planned but why am I seeing this weird behavior? This behavior may be limited to vectors.

    This raises a concern. I want to create a function that takes a vector, and removes multiple occurances of members, like this: vectA = removecopies(vectA). This may not work since vectA is made to equal a called(and modified) instance of itself. Is this the case?
    Last edited by elninio; 09-21-2008 at 01:55 AM. Reason: evil monkeys

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    I suggest that you post the smallest and simplest compilable program that demonstrates the problem.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Jun 2008
    Posts
    106
    Quote Originally Posted by laserlight View Post
    I suggest that you post the smallest and simplest compilable program that demonstrates the problem.
    I'm trying,

    cout << F[kFmap[k][namesmap[i]]] / (argc-2); worked as it should though, and all F[kFmap[k][namesmap[i]]] values are legit. I tried storing F[kFmap[k][namesmap[i]]] / (argc-2) in an intermediate variable and then make F[kFmap[k][namesmap[i]]] = midvar, casting everything to float, but that failed too.

  4. #4
    Registered User
    Join Date
    Jun 2008
    Posts
    106
    Quote Originally Posted by laserlight View Post
    I suggest that you post the smallest and simplest compilable program that demonstrates the problem.
    I don't know if this is possible as this calls multiple classes, which call various libs. But could you tell me about how vectors store values [in detail, i.e memory allocation]? Somehow the program mistakes the percentage calculation of F[n-1] to be F[n], and theres no reason for this as the loop begins a new instance each run. I'm compiling g++ with ansi option and I'm getting no warnings. ansi conforms to ISO C90, but not C99 as it is a work in progress, I'll try passing C99 ansi flag...

    here is some more info:

    F[ kFmap[k][ namesmap[i] ] ]

    kFmap[k] is vector<map<string,int> > //returns an int
    namesmap[i] is <string,int> , returns the string of truncated filenames of argv's
    F[] is vector<int> //returns an int
    Last edited by elninio; 09-21-2008 at 02:19 AM.

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    I'm trying
    Obviously, I cannot compile and run your code. In the meantime, I can only guess what kFmap, namesmap and F (F? That is a terribly undescriptive name!) are. My guess is that you are looking at a problem with integer division or floating point inaccuracy, but I am not good enough to determine anything given your code snippet.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #6
    Registered User
    Join Date
    Jun 2008
    Posts
    106
    I've added more information.

  7. #7
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    But could you tell me about how vectors store values [in detail, i.e memory allocation]?
    Since vectors are required to store their elements contiguously, they pretty much always use an internal dynamically allocated array. Quoting from Josuttis' The C++ Standard Library: "Inserting or removing elements invalidates references, pointers, and iterators that refer to the following elements. If an insertion causes reallocation, it invalidates all references, iterators, and pointers."

    I don't know if this is possible as this calls multiple classes, which call various libs.
    ...
    Somehow the program mistakes the percentage calculation of F[n-1] to be F[n], and theres no reason for this as the loop begins a new instance each run.
    So, are you sure that the problem is not elsewhere? Maybe you have a bug elsewhere, and a bug in this code, and the interaction between those two bugs are producing the current problem. Basically, you need to isolate this current code such that you can determine that it really works (and ideally write unit tests for it). If that does not fix the problem, then there is probably another bug elsewhere that needs to be fixed.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  8. #8
    Registered User
    Join Date
    Jun 2008
    Posts
    106
    Quote Originally Posted by laserlight View Post
    Since vectors are required to store their elements contiguously, they pretty much always use an internal dynamically allocated array. Quoting from Josuttis' The C++ Standard Library: "Inserting or removing elements invalidates references, pointers, and iterators that refer to the following elements. If an insertion causes reallocation, it invalidates all references, iterators, and pointers."


    So, are you sure that the problem is not elsewhere? Maybe you have a bug elsewhere, and a bug in this code, and the interaction between those two bugs are producing the current problem. Basically, you need to isolate this current code such that you can determine that it really works (and ideally write unit tests for it). If that does not fix the problem, then there is probably another bug elsewhere that needs to be fixed.
    iso c++98 doesn't tell me anything. everything works fine except for that one line, I have made sure that all the vals are in their right place, havent I? I've shown what the values of F are before the /= operation. Whatever happens before this point is redundant.

    "Inserting or removing elements invalidates references, pointers, and iterators that refer to the following elements." --> I guess this explains it doesn't it? "and iterators".

    Its bad luck for me that this shocking that this effect is recursive, although quite unprobable to start with. Same goes for the fact that iso c98 doesn't cover this issue. Right? I have made this sample program, but it works fine:

    Code:
    #include <iostream>
    #include <vector>
    using namespace std;
    
    int main(){
    	vector<int>	A;
    	A.resize(10);
    	A[0] = 10;
    	A[1] = 20;
    	A[2] = 30;
    	A[3] = 40;
    	A[4] = 50;
    	A[5] = 10;
    	A[6] = 10;
    	A[7] = 80;
    	A[8] = 90;
    	A[9] = 100;
    	
    	for (int i = 0; i < 10; i++){
    		cout << A[i] << " | ";
    		A[i] /= 10;
    		cout << A[i] << endl;
    	}
    return 0;
    }
    To be fully accurate I would have to emulate the entire sequence of events of things being passed from container to container. But, I fail to understand how this is necessary. Containers should only keep track of their assigned values - not how it was assigned in the container where it came from.
    Last edited by elninio; 09-21-2008 at 02:48 AM.

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    I have made sure that all the vals are in their right place, havent I? I've shown what the values of F are before the /= operation
    I don't know, since your code snippet does not correspond to your example output.

    "Inserting or removing elements invalidates references, pointers, and iterators that refer to the following elements." --> I guess this explains it doesn't it? "and iterators".
    I don't know, just given the information at hand.

    Same goes for the fact that iso c98 doesn't cover this issue. Right?
    The 1998 version of the C++ Standard does not guarantee that vectors store their elements contiguously. On the other hand, this is fixed in the 2003 version of the C++ Standard, and it is highly unlikely that any sane standard library implementation would have implemented vectors such that they comply with C++98 but do not comply with C++03.

    To be fully accurate I would have to emulate the entire sequence of events of things being passed from container to container.
    What you can do is to populate F, kFmap and namesmap with test data, then use them in this part of the code. When you show us this test program, show everything, from the population of the containers to both of the loops to the exact output. Do not truncate anything, do not change anything, not even the sample output.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  10. #10
    Registered User
    Join Date
    Jun 2008
    Posts
    106
    what is the g++ parameter for iso c++03? I don't think there is one (according to the man page).

  11. #11
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    what is the g++ parameter for iso c++03? I don't think there is one (according to the man page).
    You're barking up the wrong tree. I am certain that g++ is not so brain damaged as to implement vector such that it does not comply with C++03. If it did, then it would have been filed as a bug more than 5 years ago.

    Looking at your example, it is obvious that no reference, pointer or iterator can be invalidated. We're talking about things like this:
    Code:
    #include <iostream>
    #include <vector>
    
    int main()
    {
        std::vector<int> vec(1, 123);
        int& r = vec[0];
        std::cout << vec[0] << " == " << r << std::endl;
        vec.resize(vec.capacity() + 1); // r is invalidated
        vec[0] = 456;
        std::cout << vec[0] << " == " << r << std::endl;
    }
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  12. #12
    Registered User
    Join Date
    Jun 2008
    Posts
    106
    I have simplified code to demonstrate my example, please feel free to extend it to wider sets.

    edit: fixed that annoying error message at the end.

    Code:
    #include <iostream>
    #include <vector>
    #include <map>
    using namespace std;
    
    int main(){
    	vector<vector<float> > kF;
    	vector<float> F;
    	map <int, string> namesmap;
    	
    	namesmap[1] = "one";
    	namesmap[2] = "two";
    	namesmap[3] = "three";
    	namesmap[4] = "four";
    	
    	vector<map<string,int> > kFmap;
    	kFmap.resize(2);
    	kFmap[0][namesmap[1]] = 5;
    	kFmap[0][namesmap[2]] = 10;
    	kFmap[0][namesmap[3]] = 5;
    	kFmap[0][namesmap[4]] = 20;
    	
    	kFmap[1][namesmap[1]] = 5;
    	kFmap[1][namesmap[2]] = 5;
    	kFmap[1][namesmap[3]] = 5;
    	kFmap[1][namesmap[4]] = 20;
    	
    	for (unsigned int k = 0; k < 2; k++){
    		cout << "k = " << k << endl;
    		F.resize(6);
    		for (int i = 1; i <= 4; i++){
    			F[kFmap[k][namesmap[i]]]++;
    		}
    		for (int i = 1; i <= 4; i++){			
    			cout << kFmap[k][namesmap[i]] << " kFmap | ";
    			cout << F[kFmap[k][namesmap[i]]] << " | ";
    			F[kFmap[k][namesmap[i]]] /= (10); //bug
    			cout << F[kFmap[k][namesmap[i]]] << " | ";
    			cout << endl;
    		} cout << endl;
    		kF.push_back(F);
    		F.clear();
    	}
    	return 0;
    }
    Last edited by elninio; 09-21-2008 at 03:55 AM.

  13. #13
    Registered User
    Join Date
    Jun 2008
    Posts
    106
    Quote Originally Posted by laserlight View Post
    You're barking up the wrong tree. I am certain that g++ is not so brain damaged as to implement vector such that it does not comply with C++03. If it did, then it would have been filed as a bug more than 5 years ago.

    Looking at your example, it is obvious that no reference, pointer or iterator can be invalidated. We're talking about things like this:
    Code:
    #include <iostream>
    #include <vector>
    
    int main()
    {
        std::vector<int> vec(1, 123);
        int& r = vec[0];
        std::cout << vec[0] << " == " << r << std::endl;
        vec.resize(vec.capacity() + 1); // r is invalidated
        vec[0] = 456;
        std::cout << vec[0] << " == " << r << std::endl;
    }
    I was referring to pointers as the possible pointers that exist within the vector or map class during its operation.

  14. #14
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Given the complexity of your original post, I'm going to assume that this is part of some much larger program.

    When dealing with apparent memory corruption, there is always a "cause" and an "effect".

    For simple bugs, like say
    a = 42 / 0;
    the cause and effect are in the same place. As soon as the bug happens, you get to know about it.

    Memory corruption on the other hand is much trickier.

    In short, excessive analysis of where the problem appears (the effect) isn't going to help you understand the real problem (the cause). The true cause of the problem could be in a completely different area of the code.

    If you extract this code, put a minimal support environment around it, and it works, then you can be pretty sure the real problem is somewhere else.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  15. #15
    Registered User
    Join Date
    Jun 2008
    Posts
    106
    Upon further research, it appears that c++99 isn't fully supported. Some of 03 is supported, but you still pass the 99 flag to it, and it says you can also use -pedantic but it won't tell you which of 03 is in passing -c++99 and which is in pedantic.
    Last edited by elninio; 09-21-2008 at 04:16 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 1
    Last Post: 10-27-2006, 01:21 PM
  2. This seemed impossible!Can anyone help??
    By nesir in forum C Programming
    Replies: 23
    Last Post: 08-22-2006, 01:23 AM
  3. Replies: 29
    Last Post: 10-25-2005, 09:46 PM
  4. increment/decrement operators
    By ZakkWylde969 in forum C++ Programming
    Replies: 10
    Last Post: 07-10-2003, 04:17 PM
  5. Replies: 11
    Last Post: 03-25-2003, 05:13 PM