【问题标题】:C++ confusion with new and scopeC++ 混淆 new 和 scope
【发布时间】:2014-04-20 06:58:49
【问题描述】:

我正在尝试学习 C++ 以及从我在书籍和 SO 中读到的内容:

如果我使用auto x = new Object(); x 是一个指向 Object 地址的指针,它在动态内存中并且存在直到我删除它。

但是,如果我使用 Object x;auto x = Object(),它只会持续到超出范围。

在一个例子中,他们展示了这一点:

void foo()
{
  Point p = Point(0,0);
} // p is now destroyed.

我不明白的是,当我不使用 new 时返回一个对象会发生什么?它会是对象的副本吗?

这是一个我不确定的例子:

class Object
{
public:
    int X;
    static Object Foo(int y)
    {
        Object result;
        result.X = y;
        return result;
    }
};

class TestContainer
{
public:
    void Run()
    {
        for(auto i = 0; i < 10; i++)
        {
            _objects.at(i) = Object::Foo(i + (rand() % 10 + 1));
        }
    }
private:
    std::vector<Object> _objects;
};

void main()
{
    TestContainer tc;
    while(true)
    {
        tc.Run();
    }
}

请注意,我没有测试过这段代码,但我认为它消除了我的困惑。在我的主要功能中,我实例化了 TestContainer 并无休止地调用它的 Run 方法。这反过来循环调用 Object 上的静态 Foo 方法,该方法返回一个新 Object 的副本,该副本存储在一个向量中。

我的问题是,所有对象会发生什么?如果我用新对象替换对象向量中的元素 2,旧值现在是否“超出范围”并被删除?

【问题讨论】:

  • 我认为你的_objects.at(i) 表达式会抛出,因为_objects 从未指定大小。
  • @FredLarson:很好的观察。
  • 是的,谢谢弗雷德。错过了。
  • 警告:auto x = new Object();auto x = new Object; 不同。你可能想要后者。更多信息:stackoverflow.com/questions/620137/…

标签: c++ vector scope


【解决方案1】:

它会是对象的副本吗?

是的。

或者可以使用移动来代替,或者可以优化整个事物以在最终编译的程序中只生成一个实际对象。

但是,基本上,是的。

如果我用新对象替换对象向量中的元素 2,旧值现在是否“超出范围”并被删除?

是的。

顺便说一句,您在不存在的元素上使用at;要添加元素,请使用insertpush_back

【讨论】:

    【解决方案2】:

    像这样的简单类的行为很像 POD 变量。 o1=o2 按元素复制字段。所以分配的目标对象不会被删除而是被覆盖。

    超出范围的对象“消失”(因为堆栈已展开),例如一个整数。

    【讨论】:

    • 这些对象,即向量元素,并不存在于“堆栈”中。它们实际上是动态分配的!请不要使用这些过度简化的术语。
    • @Lightness:我说的不是矢量元素。我只是指出一个“对象”(由 OP 定义)在各个方面都表现得像一个 int。当它“超出范围”(范围暗示我们正在谈论本地变量)时,它确实 存在于堆栈中并且确实 停止这样做,就像一个 int 一样。所以来自“ = Object::Foo(i + (rand() % 10 + 1));”的临时对象一旦执行离开语句,它就不再存在,就像 int(2) 一样。这可能会令人困惑,但它很好,因为它解决了“所有对象会发生什么”问题;-)。
    • 无论如何,OP 都在询问向量的元素。所以,充其量,这个答案是无关紧要的! :)
    • 谢谢你的笑脸......只是OP问“当我不使用new时返回一个对象会发生什么?它会是对象的副本吗?”我回答说,不多不少——几乎无关紧要。如果我没看错你的回答,我们说的是同样的话。
    • 你说的是堆栈,这是错误的。我没有。
    【解决方案3】:

    这是一个可运行的示例,我相信它说明了这种行为:

    #include <iostream>
    
    using namespace std;
    
    class Foo {
        private:
            int id;
        public:
            Foo(int x)
                : id(x)     
            {
                cout << this->id << " is created" << endl;
            }
    
            Foo(const Foo& rhs)
                : id(rhs.id)
            {
                cout << "copied " << this->id << endl;
            }
    
            Foo& operator=(Foo rhs){
                this->id=rhs.id;
                cout << "assigned " << this->id << endl; 
                return *this;
            }
    
            ~Foo(){
                cout << this->id << " is destroyed" << endl;
            }
    
            int getID(){
                return this->id;
            }
    };
    
    Foo bar(){
        Foo f1 = Foo(1);
        cout << f1.getID() << " from bar" << endl;
        return f1;
    }
    
    int main(){
        Foo f2 = bar();
        cout << f2.getID() << " from main" << endl;
        return 0;
    }
    

    这会产生这个输出:

    1 is created
    1 from bar
    1 from main
    1 is destroyed
    

    因此,我没有看到副本或作业。我怀疑正在发生的事情是 f1 和 f2 都引用了内存中对象的同一个实例。当 f1 引用超出范围时,该对象不会被解除分配,因为该对象有另一个引用分配给它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-09
      • 2015-03-07
      • 2012-03-03
      相关资源
      最近更新 更多