【问题标题】:Set pointer to element in vector to null, then check whether pointer is null (C++)将vector中元素的指针设置为null,然后检查指针是否为null(C++)
【发布时间】:2013-08-04 20:28:00
【问题描述】:

我想将指向向量数组中某些元素的指针设置为 NULL(基于标准),然后检查元素指针是否为 NULL。如果指向该元素的指针为 NULL,则从向量数组中删除该元素。

我的编译器给我一个错误,说地址表达式必须是左值或函数指示符,我不明白为什么(代码中注释的行位置)。由于我使用& 获取值的地址,所以我没有看到指向该元素的指针是否为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;
}

【问题讨论】:

  • vector&lt;vector&lt;particle&gt;&gt; collisionlist = *new vector&lt;vector&lt;particle&gt;&gt;(); - WTF
  • 你似乎把你的指针和值弄混了......
  • @H2CO3 是 内存泄漏运算符 (new*),它是一个非标准扩展 :)
  • 您可能是 C++ 新手,但您似乎熟悉另一种语言,每个变量都需要 new。 C++ 不是这样工作的,局部变量可以被声明并自动分配。你为使它编译而生成的构造对于任何精通 C++ 的人来说都是非常令人惊讶的。正如@sehe 指出的那样,它会导致内存泄漏。
  • 你可能会从stackoverflow.com/questions/2639255/…得到一些帮助

标签: c++ null stdvector


【解决方案1】:

您正在使用&amp; 获取一个指向临时值的指针(从getxpos 返回),这是不允许的;由于临时地址将消失,因此该地址不会以任何方式有用,因此语言不允许。即使你能得到它的地址,它肯定永远不会是 NULL。

【讨论】:

  • 错字:vale 而不是 value
【解决方案2】:

noncollision[i].setxposint(NULL);

该行所做的只是将xpos 设置为零。通常术语NULL 用于指针,0 用于整数之类的东西。 NULL 通常是 0L 的宏。

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

这是不正确的,它试图从成员方法getxpos() 中获取返回值的地址并将其与NULL 进行比较。而您真正想做的只是查看函数是否返回零。所以只需将这一行更改为:

noncollision[i].getxpos() == 0

【讨论】:

  • 该更改可能会编译,但我怀疑它会产生预期的效果。我认为 0 的 x 位置是完全有效的。
  • Err...noncollision 的类型为 vector&lt;particle&gt;noncollision[i] 的类型为 particle。 @BenjaminLindley:如果是这样,那是另一个问题的主题-“如何用相同的数据类型表示'null'和'0'?”什么的。
  • @JonathanPotter 如果我想将元素保留在数组中,但使它们不可访问,我该怎么办,然后检查它们是否不可访问?是的,0 的 xpos 是有效的。
  • @user2638374:您可以使用-1 表示没有冲突。
  • @user2638374:当然,如果它适合你,请使用-1000000。诀窍是要意识到NULL0 是同一个东西。
【解决方案3】:

我会解释为什么编译器不理解你的意思。

当你写作时

&(someFunction())

您正在询问函数返回的东西的地址。但是函数返回值。值没有地址。变量有地址。

当某事物是记忆词(将包含一个值)时,它可以用作左值(左值),因为您可以将事物放入记忆词中:

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

当某物只是一个值时,它只能用作右值。以下内容无法编译,原因与您的代码无法编译的原因相同:

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 处写入内存,则会崩溃。 )

【讨论】:

  • 很好解释。 函数返回值这很容易记住:-)
【解决方案4】:

在我看来,您正在尝试跟踪“访问过”的项目,但不确定具体采用哪种方式。

您可以使用“外部”标记,而不是“修改”项目。一套在这里看起来很好。您可以在粒子列表中使用一组iterators,或者在这种情况下使用一组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

因为它可能不会达到你的预期

【讨论】:

  • 那么noncollision[i] 不是向量吗? :P
  • @JonathanPotter 你知道我删除了那条评论 :) 人们误读了。另外,可能是我对标记的理解正好相反。但我相信 OP 能够解决这个问题。
  • 实际上,我印象深刻的是,您可以仅从内存中构建一个看似合理的编译器错误 :)
  • @JonathanPotter 我实际上不是那个 ---熟练---有动力:)
  • 我稍微修改了代码示例以使其更有意义
【解决方案5】:

您似乎正在尝试检查点对是否存在碰撞。然后记录每个点是否有任何碰撞。这最好通过一个简单的标志列表来处理:

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&lt;pair&lt;particle, particle&gt;&gt;,如上所述)。

【讨论】:

    猜你喜欢
    • 2011-09-05
    • 1970-01-01
    • 2023-03-28
    • 2016-03-01
    • 1970-01-01
    • 2010-12-25
    • 1970-01-01
    • 2013-07-30
    • 2020-05-27
    相关资源
    最近更新 更多