开发者

Iterator member behavior

I was expecting the second assert in the following to pass. I'm asking for your help.

Edit: It didn't work when I had poss everywhere instead of poss_a in some places.

#include <vector>
#include <cassert>

class Sampler
{
public:
 std::vector<int*> poss;
 std::vector<int*>::const_iterator poss_it;
 Sa开发者_运维技巧mpler(std::vector<int*> poss_a) : poss(poss_a), poss_it(poss.begin())
 {
  assert( (poss[0]) == (*poss_it) ); //passes
 }
};

int main()
{
 int someInt;
 std::vector<int*> poss_a(1, &someInt);
 Sampler sampler(poss_a);
 assert( ((sampler.poss)[0]) == (*(sampler.poss_it)) ); //passes now

 return 0;
}


The poss_it(poss.begin()) line in your initializer list is pulling an iterator from the poss that is the input to the constructor, not the one that is a field of the class.

This is a scope issue. When you're in the constructor, it's fine, because your iterator is a pointer to the input to the function. When you leave the constructor however, it's pointing to the same spot in memory but now you have no idea what's at that location.

You should change the name of the input variable in the constructor. You want one that does this:

Sampler(std::vector<int*> input) : poss(input), poss_it(poss.begin())

Whereas what your current one is doing is this:

Sampler(std::vector<int*> input) : poss(input), poss_it(input.begin())


Probably getting confused over the local variables overriding the instance variables, try

#include <vector>
#include <cassert>

class Sampler
{
public:
    std::vector<int*> poss;
    std::vector<int*>::const_iterator poss_it;
    // THIS IS THE LINE I CHANGED
    Sampler(std::vector<int*> aPoss)    : poss(aPoss), poss_it(poss.begin())
    {
        assert( (poss[0]) == (*poss_it) ); //passes
    }
};

int main()
{
    int someInt;
    std::vector<int*> poss(1, &someInt);
    Sampler sampler(poss);
    assert( ((sampler.poss)[0]) == (*(sampler.poss_it)) ); //fails

    return 0;
}


You are essentially invoking undefined behavior because sampler.poss_it is an iterator into a std::vector<int*> object that was destructed before the second assert was executed.

The problem was on the line:

Sampler(std::vector<int*> poss) : poss(poss), poss_it(poss.begin())

where the first poss of poss(poss) refers to the Sampler object's poss member, the second poss of poss(poss) refers to the poss parameter, and the poss of poss_it(poss.begin()) refers again to the poss parameter (not the poss member). The poss parameter goes out of scope at the end of the constructor, so the poss parameter is destructed, meaning that the poss_it iterator is no longer valid.

To avoid this type of problem, C++ programmers almost always avoid shadowing variables. Also, a copy constructor should probably take a const-reference (to avoid pass-by-value for potentially large objects):

Sampler(const std::vector<int*>& poss_) : poss(poss_), poss_it(poss.begin())
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜