1

我是一名切换到 C++ 的 Java 程序员。我有一个类中的数据列表。我想返回存储在类变量中的列表的内容,然后生成一个新列表并将其存储在类变量中,这样我就可以开始将新数据添加到空列表中。我想我知道该怎么做,但是我想仔细检查一下,因为我是引用和 C++ 内存管理的新手,以后不希望出现愚蠢的内存泄漏。(注意,我不能轻易复制我的实际代码,所以我只是重写它,如果我输入错误,请原谅我)。

我相信正确的语法是这样的:

//mylist is typedef of a list type
mylist& temporaryList=classList;
classList=myList();
return classList;

这个语法正确吗?另外,我是否需要担心随时释放返回的变量或 classList 变量,或者 RIAA 会为我处理这一切?

很抱歉提出这么简单的问题,但感谢您确认我的假设。

4

3 回答 3

2
mylist& temporaryList=classList;

tempraryList是参考。当你改变classList时,它也会改变。尝试这个:

mylist tempraryList = classList;

这将复制 mylist 的复制构造函数,创建一个新的而不是仅仅为另一个别名。


return classList;

这将返回您刚刚决定的应该是新列表的列表。你想回来temporaryList。但是,请确保它不是通过引用返回的,因为temporaryList它会超出范围(清理自身,因为它是在堆栈上分配的)并且您最终会得到一个悬空引用。

同样,通常,不是分配默认构造函数的结果,类可能会提供一种reset函数来做到这一点,而无需另一个对象的开销。

于 2012-06-16T00:22:43.850 回答
1

正如@chris 指出的那样,您在使用引用时遇到了问题,引用具有很好的功能,即它们以几乎没有成本为实际对象别名,但在您的情况下,这意味着当您重置成员列表时,您正在重置您程序中的唯一列表。

正如@chris 还指出的那样,对您的代码的简单天真修复是复制列表,然后重置原始列表:

mylist getAndClear() {
   mylist temporaryList=classList;    // make a copy
   classList=myList();                // reset the internal
   return temporaryList;              // return the **copy**
}

现在,这种方法的问题在于,当您知道原始列表将立即被销毁时,您会产生复制成本。您可以通过使用复制和交换习语(*)来避免该成本:

mylist getAndClear() { mylist tmp; // 空交换(tmp, classList); // 交换内容,现在 classList 为空 // tmp 保存数据 return tmp; }

这是假设这mylist是一个std::list. 如果不是,请确保您实现swap(或在 C++11 中移动构造函数,这将启用高效的std::swap)。


(*)虽然这似乎不是复制和交换习语的直接应用,但实际上是,要应用的修改正在清除列表。执行复制并在副本上应用更改(在这种情况下避免复制,因为更改正在清空它),然后在操作成功完成后交换内容。

于 2012-06-16T01:21:38.257 回答
0

克里斯提到使用成员函数来重置或清除对象,如下所示:

mylist tmp = classList;
classList.clear();
return tmp;

但是您通常可以通过首先避免复制来做得更好。

mylist tmp;
std::swap(tmp,classList);
return tmp;

另外,我是否需要担心随时释放返回的变量或 classList 变量,或者 RIAA 会为我处理这一切?

你不需要delete资源,除非你new在某个地方。如果你确实使用new了,那么你也应该使用智能指针,这样你仍然不需要delete任何东西。

了解来自 Java 的 C++ 的最重要的事情之一是 C++ 对象默认是类值对象。那是:

class A {
    bool bar_called;
public:
    A() : bar_called(false) {}
    void bar() { bar_called = true; }
    bool has_bar_been_called_on_this_object() { return bar_called; }
};

void foo(A a) {
    a.bar();
}

int main() {
    A a;
    foo(a);
    std::cout << a.has_bar_been_called_on_this_object() << '\n';
}

输出将指示 bar尚未被调用a。Java 使用但试图隐藏指针。因此,一旦您弄清楚 C++ 中的指针,事情对您来说应该更有意义,然后您将能够弄清楚如何使用指针。

Object o = new Object(); // Java hides the fact that o is a pointer to an Object, but fails to hide the consequences
Object b = o; // b is a pointer to an object, the same Object o points to.

// Equivalent C++
Object *o = new Object();
Object *b = o;

从您提供的 C++ 代码来看,在 Java 中,您会按照您的要求执行以下操作:

mylist tmp = classList;
classList = new mylist();
return tmp;

C++ 中的等价物是:

mylist *tmp = classList; // classList is a pointer to a new'd up list.
classList = new mylist();
return tmp;

然而,这不是惯用的 C++。在 C++ 中你通常不想使用指针,如果你想使用智能指针

std::shared_ptr<mylist> tmp = classList; // classList is a std::shared_ptr<mylist>
classList = std::make_shared<mylist>();
return tmp;

或者

std::unique_ptr<mylist> tmp = std::move(classList); // classList is a unique_ptr
classList = std::unique_ptr<mylist>(new mylist()); // careful here, don't go calling a bunch of functions inside the mylist initializer, it's dangerous for reason beyond the scope of this post
return tmp;

但是 C++ 的方式实际上是完全避免使用指针。

mylist tmp; // classList is not a pointer at all
std::swap(tmp,classList); // the values of classList and tmp are swapped
return tmp; // tmp is returned by value, tmp has the same value as classList, but is not the same object, tmp and classList are objects, not pointers to objects as they are in Java or in the above C++ examples.
于 2012-06-16T01:14:56.237 回答