-2

I'm currently programming something needing vectors. I have two nested loops;

for (size_t i = 0; i < m_neurons.size(); i++) {
        for (size_t j = 0; j < m_neurons[0].m_weights.size(); j++) {

        }
}

This section is the one we are interested in:

    d.out ("i == " + std::to_string (i));
    d.out ("m_neurons.size() == " + std::to_string (m_neurons.size()));
    d.out ("m_neurons[i].m_weights.size() == " + std::to_string (m_neurons.at(i).m_weights.size()));
    d.out ("m_neurons[i].m_weights.size() == " + std::to_string (m_neurons.at(i).m_weights.size()));
    for (size_t j = 0; j < m_neurons[0].m_weights.size(); j++) {

I print out some sizes and then, I want C++ to loop through the vector; easy enough, right?

Except this happens:

i == 0
m_neurons.size() == 1
m_neurons[i].m_weights.size() == 4
m_neurons[i].m_weights.size() == 4
terminate called after throwing an instance of 'std::out_of_range'
  what():  vector::_M_range_check: __n (which is 0) >= this->size() (which is 0)
Aborted (Speicherabzug geschrieben)
[maximilian@new-host library]$ 

1) Somehow the vector gets emptied 2) Somehow, the collection of the data is treated like I used .at (int index)

I have:

  • tried alternating between vector.at() and vector[]
  • deleted the executable and recompiled (multiple times)
  • rebooted my pc [dunno, might help]
  • investigated with GDB (the vector changed value from one step to the other)
  • Used my mediocre googling skills to search something similar.
  • Played a bit with the content of those vectors

I know that:

  • The vector is NOT changed in between
  • It is exactly THIS line of code that bugs out [because I have a printing s tatement exactly after]
  • I recall it working a bit earlier in the day

Now my Questions are:

  1. Is this a known issue/feature?
  2. What caused it?
  3. How can I fix it?

EDIT:

I made some code that boils down the problem. Seems to work fine. The thing is: NOTHING at all changes between my code and the one there. What could be the thing that triggers the bug? As said: in dbg, the size of the vector changes from one step to the other

#include <iostream> 
#include <vector>
#include "debugMachine.h"

class bar {
    public:
    bar (std::vector<double> i) {
        foobarmiz = i;
    }
    std::vector<double> foobarmiz;
};

class foo {
    public:
    std::vector<bar> foobar;
    void test (std::vector<double>& expected) {
        d.out ("HI");
        for (size_t i = 0; i < foobar.size(); i++) {
            d.out ("HI2");
            d.out ("i == " + std::to_string (i));
            d.out ("m_neurons.size() == " + std::to_string (foobar.size()));
            d.out ("m_neurons[i].m_weights.size() == " + std::to_string (foobar.at(i).foobarmiz.size()));
            d.out ("m_neurons[i].m_weights.size() == " + std::to_string (foobar.at(i).foobarmiz.size()));
            for (size_t j = 0; j < foobar[0].foobarmiz.size(); j++) {
                d.info ("Gonna change weights");
                foobar.at(i).foobarmiz[j] +=1; 
            }
            d.out ("out of backward");
        }
    }
} f;

int main () {
    d.write = true;
    std::vector<double> test {1.0f, 2.0f, 3.0f, 5.34f};
    f.foobar.push_back (bar (test));
    f.foobar.push_back (bar (test));
    f.foobar.push_back (bar (test));
    f.test (test);
}

Here is the entirity of the function that bugs out:

void CLayer::m_backward (std::vector<double>& expected) {
    d.out ("HI");
    for (size_t i = 0; i < m_neurons.size(); i++) {
        d.out ("HI2");
        d.out ("i == " + std::to_string (i));
        d.out ("m_neurons.size() == " + std::to_string (m_neurons.size()));
        d.out ("m_neurons[i].m_weights.size() == " + std::to_string (m_neurons.at(i).m_weights.size()));
        d.out ("m_neurons[i].m_weights.size() == " + std::to_string (m_neurons.at(i).m_weights.size()));
        for (size_t j = 0; j < m_neurons[0].m_weights.size(); j++) {
            d.info ("Gonna change weights");
            d.info ("m_weights before : " + std::to_string(m_neurons.at(i).m_weights.at(j)));
            m_neurons.at(i).m_weights[j] -= (0.003f * -(m_expected.at(i) - m_output.at(i)) * m_output.at(i) * (1 - m_output.at(i)) * m_input.at(j)); 
            d.info ("m_weights after : " + std::to_string(m_neurons[i].m_weights[j]));
        }
        d.out ("out of backward");
    }
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 2
    There's rarely any _"magic"_ involved with programming. I'd suppose you did something wrong. Post a [MCVE] that reproduces the behavior you claim. May be we can help you spot the mistake then. –  Feb 03 '18 at 16:05
  • 2
    1) No, it's a bug in your program, 2) A bug in your program, 3) Figure out what the bug is. Without a [mcve], a minimal example that reliably reproduces the bug and that anyone can compile, run, and debug for themselves, it's unlikely that anyone on stackoverflow.com will be able to give you any more information. – Sam Varshavchik Feb 03 '18 at 16:06
  • 3
    Why are you using `for (size_t j = 0; j < m_neurons[0].m_weights.size(); j++)` instead of `for (size_t j = 0; j < m_neurons[i].m_weights.size(); j++)` ? – Victor Padureanu Feb 03 '18 at 16:09
  • Undefined behavior can sometimes pass for magic. – François Andrieux Feb 03 '18 at 16:16
  • @FrançoisAndrieux Since when is assembly code emitted by a compiler a synonym for _magic_? But yes, there's the _cargo cult_ thing ;-) ... –  Feb 03 '18 at 16:17
  • @VictorPadureanu I wanted to eliminate the possibility of i not being what I want – Linuxer4Fun Feb 03 '18 at 16:18
  • @TheDude I just created it ;) Thing is that it worked somehow (which is rather weird) – Linuxer4Fun Feb 03 '18 at 16:21
  • _@Linuxer4Fun_ Well, @Francois might have been right with their assumption about _undefined behavior_ caused by something elsewhere not shown in the MCVE. Don't join the _cargo cult_ man. BTW, gdb supports to watch particular memory addresses for changing values (pro tip!). –  Feb 03 '18 at 16:26
  • @TheDude what do you mean by "MCVE"? If you want to see the entire function I can show it to you. Since there is no multithreading involved, it should suffice – Linuxer4Fun Feb 03 '18 at 16:27
  • @Linuxer4Fun _"what do you mean by "MCVE"?"_ It's just the acronym for [MCVE]. –  Feb 03 '18 at 16:27
  • @TheDude O sorry. I'ma edit the thread and add the complete function in a sec :) – Linuxer4Fun Feb 03 '18 at 16:28
  • `for (size_t j = 0; j < foobar[0].foobarmiz.size(); j++) {` should be `for (size_t j = 0; j < foobar[i].foobarmiz.size(); j++) {` and it works just because `foobar[0].foobarmiz.size() == foobar[i].foobarmiz.size()` in your sample – Victor Padureanu Feb 03 '18 at 16:30
  • @VictorPadureanu even when changing my MCVE like you suggested, it still runs smoothly – Linuxer4Fun Feb 03 '18 at 16:32
  • If you change your sample in the main function to add a bigger length vector first in the f.foobar and after that a smaller length vector you will get the out of bounds error. – Victor Padureanu Feb 03 '18 at 16:35
  • Wait gonna update it – Linuxer4Fun Feb 03 '18 at 16:37
  • @Linuxer4Fun _"Wait gonna update it"_ Take care not to make your question being a _moving target_, that's not really helpful. –  Feb 03 '18 at 16:38
  • @VictorPadureanu nope, it still runs smoothly (updated code: https://hastebin.com/xosagagiqo.cpp) – Linuxer4Fun Feb 03 '18 at 16:40
  • @TheDude no, from now on I will only add relevant stuff by means of hastebin :) – Linuxer4Fun Feb 03 '18 at 16:40
  • @Linuxer4Fun No, links to code outside of your question aren't useful either. –  Feb 03 '18 at 16:41
  • @TheDude O sorry, didnt know that. – Linuxer4Fun Feb 03 '18 at 16:42
  • What I am trying to say is that the previous code with `foobar[0].foobarmiz.size()` will give the error you had before and `foobar[i].foobarmiz.size()` will not give the error – Victor Padureanu Feb 03 '18 at 16:48
  • @VictorPadureanu nope, both work for me – Linuxer4Fun Feb 03 '18 at 16:51

1 Answers1

0

This is the sample that gives the problem.

#include <string>
#include <iostream> 
#include <vector>

class bar {
public:
    bar(std::vector<double> i) {
        foobarmiz = i;
    }
    std::vector<double> foobarmiz;
};

class foo {
public:
    std::vector<bar> foobar;
    void test(std::vector<double>& expected) {
        std::cout << ("HI");
        for (size_t i = 0; i < foobar.size(); i++) {
            std::cout << ("HI2") << std::endl;
            std::cout << ("i == " + std::to_string(i)) << std::endl;
            std::cout << ("m_neurons.size() == " + std::to_string(foobar.size())) << std::endl;
            std::cout << ("m_neurons[i].m_weights.size() == " + std::to_string(foobar.at(i).foobarmiz.size())) << std::endl;
            std::cout << ("m_neurons[i].m_weights.size() == " + std::to_string(foobar.at(i).foobarmiz.size())) << std::endl;
            for (size_t j = 0; j < foobar[0].foobarmiz.size(); j++) { // because of this line
                std::cout << ("Gonna change weights") << std::endl;
                foobar.at(i).foobarmiz[j] += 1;
            }
            std::cout << ("out of backward") << std::endl;
        }
    }
} f;

int main()
{
    std::vector<double> test{ 1.0f, 2.0f, 3.0f, 5.34f };
    f.foobar.push_back(bar(test));
    std::vector<double> test2{ 1.0f, 23.3f, 2.1f };
    f.foobar.push_back(bar(test2));
    std::vector<double> test3{ 1.0f, 23.3f };
    f.foobar.push_back(bar(test3));
    f.test(test);
}
Victor Padureanu
  • 604
  • 1
  • 7
  • 12
  • thanks :) Ima look if it suffices to simply change [0] to [i]. – Linuxer4Fun Feb 03 '18 at 17:04
  • It does not unfortunately – Linuxer4Fun Feb 03 '18 at 17:05
  • I would suggest adding a data breakpoint to the value that changes and see when it happens. – Victor Padureanu Feb 03 '18 at 17:12
  • what is a data breakpoint? Because I already checked with GDB what happens there – Linuxer4Fun Feb 03 '18 at 17:15
  • https://stackoverflow.com/questions/58851/can-i-set-a-breakpoint-on-memory-access-in-gdb – Victor Padureanu Feb 03 '18 at 17:30
  • Thanks :) I'ma investigate now :P – Linuxer4Fun Feb 03 '18 at 17:54
  • somehow I'm facing problems with setting the breakpoint: (gdb) rwatch &m_neurons[0].m_weights Expression cannot be implemented with read/access watchpoint. (gdb) rwatch m_neurons[0].m_weights Expression cannot be implemented with read/access watchpoint. (gdb) rwatch *m_neurons[0].m_weights No symbol "operator*" in current context. (gdb) rwatch *(m_neurons[0].m_weights) No symbol "operator*" in current context. (gdb) rwatch &(m_neurons[0].m_weights) Expression cannot be implemented with read/access watchpoint. (gdb) rwatch (m_neurons[0].m_weights) – Linuxer4Fun Feb 03 '18 at 18:36