1

I would like to set pointers to some elements in my vector array to NULL (based on a criteria), and then check whether an element pointer is NULL. If the pointer pointing that element is NULL, I remove the element from my vector array.

My compiler is giving me an error, saying that the address expression must be an lvalue or function designator and I do not understand why (line location commented in code). Since I am taking the address of the value using &, am I not seeing if the pointer pointing to that element is NULL?

I included the preceding code as the error may lie there,

Relevant code:

vector<particle> pl = c.particlelist;
vector<particle> noncollision = c.particlelist;
vector<vector<particle>> collisionlist = new vector<vector<particle>>();
for (int i = 0; i < c.numparticles-1; i++){
    particle first = pl[i];
    for (int j = i+1; j < c.numparticles; j++)
    {
        particle second  = pl[j];
        double d = distance(first, second);
        if (d==0)
        {
            vector<particle> temp = {pl[i], pl[j]};
    collisionlist.push_back(temp);
            noncollision[i].setxposint(NULL); 
            noncollision[j].setxposint(NULL);
        }
        else
        {
        }
    }
}
int j = 0;
for (int i = 0; i < noncollision.size(); i++)
{
    if (&(noncollision[i].getxpos()) == NULL) ////// ERROR HERE
    {
        noncollision.erase(noncollision.begin()+i);
    }
    else
    {
        j++;
    }
}

I am new to C++, and if you could suggest a more elegant way to do this, or a fix, it would be much appreciated. I also assume that my method of setting the pointer to an element, noncollision[i].setxposint(NULL); is correct? Can I return an integer using a function, and take the address?

Functions for getxpos and setxposint:

int particle::getxpos(){
return xpos;
}

void particle::setxposint(int b){
xpos = b;
}
user2638374
  • 37
  • 1
  • 7
  • 6
    `vector> collisionlist = *new vector>();` - WTF –  Aug 04 '13 at 20:31
  • You seem to be getting your pointers and values mixed up... – Sinkingpoint Aug 04 '13 at 20:33
  • @H2CO3 Pardon me? There is no need for blasphemous language; any constructive criticism is welcomed, but please do not offend me. We were all beginners at one point. – user2638374 Aug 04 '13 at 20:34
  • You're taking the address of an `int` value and comparing it to null, which is not a valid operation. The address won't be null. Likewise your `setxpostint(NULL)` call would try to set an integer to null and that does not make sense. `NULL` is defined as `0` and while this is arithmetically valid, it does not do what you want it to do. I also share H2CO3's confusion at that syntax - no idea where you picked it up from, it's just not something one should use. – DUman Aug 04 '13 at 20:35
  • @user2638374 C'mon, let's not start this "we were all beginners" stuff over... It's been explained zillions of times on SO why `Foo f = *new Foo` is bad, I suggest you do some searching around here for an explanation. (In the meantime, you might as well think about this a bit deeper - I'm sure you will understand it at some point.) –  Aug 04 '13 at 20:38
  • 11
    @H2CO3 that's the _memory leak operator_ (`new*`), it's a non-standard extension :) – sehe Aug 04 '13 at 20:40
  • @H2CO3 Thanks for feedback. I will look around SO in more depth. – user2638374 Aug 04 '13 at 20:41
  • @sehe Upvoting that until my mouse breaks! :D (probably tomorrow, run out of comment votes today :/ ) –  Aug 04 '13 at 20:42
  • H2CO3 is one of the most pious people on StackOverflow so coming from him **WTF** most certainly translates to _Well That's Funny_. – Captain Obvlious Aug 04 '13 at 20:45
  • @CaptainObvlious ...and "RTFM" stands for "Read the Formatted I/O Manual", of course. –  Aug 04 '13 at 20:46
  • 3
    You may be new to C++ but it appears you're familiar with another language that requires `new` for each variable. C++ doesn't work that way, local variables can just be declared and they're automatically allocated. The construct you generated to make it compile is extremely surprising to anyone well versed in C++. And as @sehe points out it causes a memory leak. – Mark Ransom Aug 04 '13 at 20:49
  • 1
    You might get some help from http://stackoverflow.com/questions/2639255/c-return-a-null-object-if-search-result-not-found – Mark Ransom Aug 04 '13 at 20:55
  • @CaptainObvlious [are you sure](https://twitter.com/H2CO3_iOS/status/326444346633236480/photo/1)? – sehe Aug 04 '13 at 21:06

5 Answers5

3

You're using & to take a pointer to a temporary vale (the return from getxpos) which isn't allowed; since a temporary will be going away, the address won't be useful in any way so the language doesn't allow it. It certainly wouldn't ever be NULL even if you could get its address.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
2

noncollision[i].setxposint(NULL);

All that line is doing is setting xpos to zero. Generally the term NULL is used with pointers, and 0 is used with things like integers. NULL is usually a macro for 0L anyway.

&(noncollision[i].getxpos()) == NULL

What this is doing, which is incorrect, is attempting to take the address of the return value from the member method getxpos() and compare it to NULL. Whereas what you really want to do is simply see if the function returns zero. So simply change this line to:

noncollision[i].getxpos() == 0

sehe
  • 374,641
  • 47
  • 450
  • 633
Jonathan Potter
  • 36,172
  • 4
  • 64
  • 79
  • 1
    That change may compile, but I doubt it will have the intended effect. I would think an x position of 0 is perfectly valid. – Benjamin Lindley Aug 04 '13 at 20:40
  • Err... `noncollision` is of type `vector`, `noncollision[i]` is of type `particle`. @BenjaminLindley: if so that's the subject for another question - "How to represent 'null' and '0' with the same data type?" or something. – Jonathan Potter Aug 04 '13 at 20:44
  • @JonathanPotter What can I do if I want to keep the elements in an array, but make them inaccessible, and then check if they are inaccessible? And yes, xpos of 0 is valid. – user2638374 Aug 04 '13 at 20:44
  • Well, I'm generally of the opinion that making changes to code just to shut up the compiler is not really helpful to anybody. – Benjamin Lindley Aug 04 '13 at 20:48
  • @BenjaminLindley: Fair enough, but if someone is clearly confused about why their code doesn't compile it seems reasonable to me to at least explain to them why, not just criticise their code in the comments. – Jonathan Potter Aug 04 '13 at 20:49
  • 1
    @user2638374: You could use `-1` to mean no collision. – Jonathan Potter Aug 04 '13 at 20:51
  • @JonathanPotter Nice suggestion. Unfortunately, -1 is also valid at this point in the code, since I have periodic boundary conditions on the particles in my 'box'. I.e. if a particle gets to the edge, it simply reappears immediately opposite. Since I know the dimensions of the box in advance, I could use a very large number. – user2638374 Aug 04 '13 at 20:55
  • 1
    @user2638374: Sure, use `-1000000` if it works for you. The trick is to realise that `NULL` and `0` are the same thing. – Jonathan Potter Aug 04 '13 at 20:56
  • @user2638374 I've given my take on that in my answer – sehe Aug 04 '13 at 20:56
2

I'll explain why the compiler doesn't understand what you mean.

When you write

&(someFunction())

you are asking for the address of the thing that the function returns. But functions return values. A value doesn't have an address. Variables have addresses.

When something is a word of memory (which will contain a value), it can be used as an lvalue (left-value), because you can put things into that word of memory:

int b = 1; //make room for an `int` on the stack, then put a `1` there.

When something is just a value, it can only ever be used as an rvalue. The following would not compile, for the same reason that your code would not:

int b; //make room for an `int` on the stack.
42 = b; //ERROR, this makes no sense.
if (42 == NULL) { std::cout << "this is never true" << std::endl; }
&42; //ERROR, 42 isn't a piece of memory, it's a value.

(Caveat: you can use values to refer to words in memory: this usage is called a pointer, e.g.

int b = 1;
*((int *)(42)) = b;

meaning "put the value of b into the memory which has the address 42. This compiles fine (but crashes if you're not allowed to write to the memory at 42.)

user234461
  • 1,133
  • 12
  • 29
1

It seems that you are trying to check pairs of points for collisions. You then record for each point whether it has any collision. This is best handled by a simple list of flags:

std::vector<bool> has_collision(c.numparticles, false); // init: no collisions found

Afterwards:

    if (d==0)
    {
        has_collision[i] = true;
        has_collision[j] = true;
    }

At the end, iterate over the list of flags and get the points that have no collisions:

for (size_t i = 0; i < c.numparticles; ++i)
{
    if (!has_collision[i])
    {
        // whatever
        // possibly push_back pl[i] into some list
    }
}

In addition: using a vector to hold a pair (i,j) of points is confusing. Standard library has the std::pair type for purposes such as this.

Also: you don't need explicit dynamic allocation (new); let Standard Library manage memory for you in a safe, non-confusing way. Instead of

vector<vector<particle>> collisionlist = *new vector<vector<particle>>();

Use

vector<vector<particle>> collisionlist;

(or vector<pair<particle, particle>>, as described above).

anatolyg
  • 26,506
  • 9
  • 60
  • 134
1

It looks to me you're trying to keep track of 'visited' items, not sure exactly in which way.

Instead of "modifying" the items, you could use an "external" mark. A set looks to be fine here. You could use a set of iterators into the particle list, or in this case a set of indices (i,j) which will likely be more stable.

Here's a start:

#include <vector>
#include <set>

struct particle { };

double distance(particle const&, particle const&) { return 1.0; }

struct context
{
    std::size_t numparticles;
    std::vector<particle> particlelist;

    context() : numparticles(100), particlelist(numparticles) {}
};

static context c;

int main()
{
    using std::vector;
    using std::size_t;

    vector<particle> pl = c.particlelist;
    vector<vector<particle>> collisionlist;

    std::set<size_t> collision;

    for(size_t i = 0; i < c.numparticles-1; i++)
    {
        particle first = pl[i];
        for(size_t j = i+1; j < c.numparticles; j++)
        {
            particle second  = pl[j];
            double d = distance(first, second);
            if(d < 0.0001)
            {
                collisionlist.push_back({pl[i], pl[j]});
                collision.insert(i);
                collision.insert(j);
            }
            else
            {
            }
        }
    }

    for(size_t i = 0; i < pl.size(); i++)
    {
        if(collision.end() != collision.find(i))
        {
            // do something
        }
    }

    // alternatively
    for (int index : collision)
    {
        particle& p = pl[index];
        // do something
    }
}

NOTE Be very very wary of floating point comparison like

 if (d==0.0) // uhoh

because it will likely not do what you expect

Community
  • 1
  • 1
sehe
  • 374,641
  • 47
  • 450
  • 633