Установите указатель на элемент в векторе равным нулю, затем проверьте, является ли указатель нулевым (С++)

Я хотел бы установить указатели на некоторые элементы в моем векторном массиве на NULL (на основе критерия), а затем проверить, является ли указатель элемента NULL. Если указатель, указывающий на этот элемент, равен NULL, я удаляю этот элемент из векторного массива.

Мой компилятор выдает ошибку, говоря, что адресное выражение должно быть lvalue или указателем функции, и я не понимаю, почему (местоположение строки прокомментировано в коде). Поскольку я беру адрес значения, используя &, я не вижу, является ли указатель, указывающий на этот элемент, NULL?

Я включил предыдущий код, так как ошибка может заключаться в нем,

Соответствующий код:

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++;
    }
}

Я новичок в C++, и если бы вы могли предложить более элегантный способ сделать это или исправить, я был бы очень признателен. Я также предполагаю, что мой метод установки указателя на элемент noncollision[i].setxposint(NULL); верен? Могу ли я вернуть целое число с помощью функции и взять адрес?

Функции для getxpos и setxposint:

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

void particle::setxposint(int b){
xpos = b;
}

person user2638374    schedule 04.08.2013    source источник
comment
vector<vector<particle>> collisionlist = *new vector<vector<particle>>(); - ВТФ   -  person    schedule 05.08.2013
comment
Кажется, вы путаете свои указатели и значения...   -  person Sinkingpoint    schedule 05.08.2013
comment
@H2CO3 Простите? Нет нужды в богохульных выражениях; любая конструктивная критика приветствуется, но прошу не обижать меня. Все мы когда-то были новичками.   -  person user2638374    schedule 05.08.2013
comment
Вы берете адрес значения int и сравниваете его с нулем, что не является допустимой операцией. Адрес не будет нулевым. Точно так же ваш вызов setxpostint(NULL) попытается установить целое число равным нулю, и это не имеет смысла. NULL определяется как 0, и хотя это арифметически допустимо, оно не делает того, что вы хотите. Я также разделяю путаницу H2CO3 в этом синтаксисе - понятия не имею, откуда вы его взяли, это просто не то, что следует использовать.   -  person DUman    schedule 05.08.2013
comment
@user2638374 user2638374 Да ладно, давайте не будем начинать с этого, мы все были новичками ... Это объяснялось миллионы раз, почему Foo f = *new Foo это плохо, я предлагаю вам поискать объяснение здесь. (Тем временем вы могли бы подумать об этом немного глубже — я уверен, что в какой-то момент вы это поймете.)   -  person    schedule 05.08.2013
comment
@H2CO3 это оператор утечки памяти (new*), это нестандартное расширение :)   -  person sehe    schedule 05.08.2013
comment
@H2CO3 Спасибо за отзыв. Я посмотрю вокруг SO более подробно.   -  person user2638374    schedule 05.08.2013
comment
@sehe Голосую за это, пока моя мышь не сломается! :D (скорее всего завтра, сегодня закончились голоса в комментариях :/ )   -  person    schedule 05.08.2013
comment
H2CO3 — один из самых благочестивых людей в StackOverflow, поэтому его слова WTF наверняка переводятся как Ну, это смешно.   -  person Captain Obvlious    schedule 05.08.2013
comment
@CaptainObvlious ... и RTFM, конечно же, означает «Прочитайте руководство по форматированному вводу-выводу».   -  person    schedule 05.08.2013
comment
Вы можете быть новичком в C++, но похоже, что вы знакомы с другим языком, который требует new для каждой переменной. С++ так не работает, можно просто объявить локальные переменные, и они будут автоматически выделены. Созданная вами конструкция для ее компиляции чрезвычайно удивит любого, кто хорошо разбирается в C++. И, как указывает @sehe, это вызывает утечку памяти.   -  person Mark Ransom    schedule 05.08.2013
comment
Вы можете получить помощь от stackoverflow.com/questions/2639255/   -  person Mark Ransom    schedule 05.08.2013
comment
@CaptainObvlious вы уверены?   -  person sehe    schedule 05.08.2013


Ответы (5)


Мне кажется, вы пытаетесь отслеживать «посещенные» элементы, не зная точно, каким образом.

Вместо «изменения» элементов вы можете использовать «внешнюю» метку. Набор выглядит здесь хорошо. Вы можете использовать набор iterator в списке частиц или, в данном случае, набор indices (i,j), который, вероятно, будет более стабильным.

Вот начало:

#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
    }
}

ПРИМЕЧАНИЕ Будьте очень осторожны при сравнении с плавающей запятой, например

 if (d==0.0) // uhoh

потому что это, вероятно, не будет делать то, что вы ожидаете

person sehe    schedule 04.08.2013
comment
Значит, noncollision[i] не является вектором? :П - person Jonathan Potter; 05.08.2013
comment
@JonathanPotter, вы знаете, я удалил этот комментарий :) Люди неправильно поняли. Кроме того, возможно, я понял маркировку именно наоборот. Но я верю, что ОП сможет это исправить. - person sehe; 05.08.2013
comment
На самом деле я был впечатлен тем, что вы могли создать правдоподобно выглядящую ошибку компилятора, предположительно, только из памяти :) - person Jonathan Potter; 05.08.2013
comment
@JonathanPotter На самом деле я не такой --- квалифицированный --- мотивированный :) - person sehe; 05.08.2013
comment
Я немного изменил пример кода, чтобы сделать его более понятным. - person sehe; 05.08.2013

Вы используете & для получения указателя на временное значение (возврат из getxpos), что не разрешено; поскольку временный адрес будет уходить, адрес никоим образом не будет полезен, поэтому язык не позволяет этого. Это определенно никогда не было бы NULL, даже если бы вы могли получить его адрес.

person Mark Ransom    schedule 04.08.2013
comment
Опечатка: vale вместо value - person Wolf; 13.05.2015

noncollision[i].setxposint(NULL);

Все, что делает эта строка, это устанавливает xpos в ноль. Обычно термин NULL используется с указателями, а 0 используется с такими вещами, как целые числа. NULL в любом случае обычно является макросом для 0L.

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

Что это делает, что неверно, пытается взять адрес возвращаемого значения из метода-члена getxpos() и сравнить его с NULL. В то время как то, что вы действительно хотите сделать, это просто посмотреть, возвращает ли функция ноль. Поэтому просто измените эту строку на:

noncollision[i].getxpos() == 0

person Jonathan Potter    schedule 04.08.2013
comment
Это изменение может скомпилироваться, но я сомневаюсь, что оно будет иметь ожидаемый эффект. Я бы подумал, что позиция x, равная 0, вполне допустима. - person Benjamin Lindley; 05.08.2013
comment
Э-э... noncollision относится к типу vector<particle>, noncollision[i] относится к типу particle. @BenjaminLindley: если да, то это тема для другого вопроса — как представить «null» и «0» с одним и тем же типом данных? или что-то. - person Jonathan Potter; 05.08.2013
comment
@JonathanPotter Что мне делать, если я хочу сохранить элементы в массиве, но сделать их недоступными, а затем проверить, недоступны ли они? И да, xpos 0 действителен. - person user2638374; 05.08.2013
comment
Ну, я в целом придерживаюсь мнения, что внесение изменений в код только для того, чтобы заткнуть компилятор, на самом деле никому не поможет. - person Benjamin Lindley; 05.08.2013
comment
@BenjaminLindley: Достаточно справедливо, но если кто-то явно смущен тем, почему их код не компилируется, мне кажется разумным хотя бы объяснить им, почему, а не просто критиковать их код в комментариях. - person Jonathan Potter; 05.08.2013
comment
@ user2638374: Вы можете использовать -1, чтобы не было столкновений. - person Jonathan Potter; 05.08.2013
comment
@JonathanPotter Хорошее предложение. К сожалению, -1 также допустимо в этом месте кода, поскольку у меня есть периодические граничные условия для частиц в моем «ящике». т.е. если частица попадает на край, она просто снова появляется сразу напротив. Поскольку я заранее знаю размеры коробки, я мог бы использовать очень большое число. - person user2638374; 05.08.2013
comment
@user2638374: Конечно, используйте -1000000, если вам это подходит. Хитрость заключается в том, чтобы понять, что NULL и 0 — это одно и то же. - person Jonathan Potter; 05.08.2013
comment
@user2638374 user2638374 Я высказал свое мнение об этом в своем ответе. - person sehe; 05.08.2013

Я объясню, почему компилятор не понимает, что вы имеете в виду.

Когда вы пишете

&(someFunction())

вы запрашиваете адрес того, что возвращает функция. Но функции возвращают значения. Значение не имеет адреса. Переменные имеют адреса.

Когда что-то является словом памяти (которое будет содержать значение), его можно использовать как lvalue (левое значение), потому что вы можете помещать вещи в это слово памяти:

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

Когда что-то является просто значением, его можно использовать только как rvalue. Следующее не будет компилироваться по той же причине, что и ваш код:

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.

(Предостережение: вы можете использовать значения для ссылки на слова в памяти: такое использование называется указателем, например.

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

что означает «поместить значение b в память с адресом 42. Это компилируется нормально (но вылетает, если вам не разрешено записывать в память по адресу 42).

person user234461    schedule 04.08.2013
comment
Хорошо объяснил. функции возвращают значения это легко запомнить :-) - person Wolf; 13.05.2015

Похоже, вы пытаетесь проверить пары точек на коллизии. Затем вы записываете для каждой точки, имеет ли она какое-либо столкновение. Лучше всего с этим справляется простой список флагов:

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

После:

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

В конце перебираем список флагов и получаем точки, в которых нет коллизий:

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

Кроме того: использование vector для хранения пары (i,j) точек сбивает с толку. Стандартная библиотека имеет тип std::pair для таких целей.

Кроме того: вам не нужно явное динамическое выделение (new); позвольте стандартной библиотеке управлять памятью безопасным и не запутанным способом. Вместо

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

Использовать

vector<vector<particle>> collisionlist;

(или vector<pair<particle, particle>>, как описано выше).

person anatolyg    schedule 04.08.2013