确认基本 C++ 语法

confirmation of basic c++ syntax

本文关键字:语法 C++ 确认      更新时间:2023-10-16

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

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

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

此语法正确吗? 另外,我是否必须担心随时释放返回的变量或类列表变量,或者RIAA会为我处理这一切吗?

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

mylist& temporaryList=classList;

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

mylist tempraryList = classList;

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


return classList;

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

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

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

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

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

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

mylist getAndClear() { 我的利斯特TMP; 空 swap( tmp, classList ); 交换内容,现在类列表为空 TMP 保存数据 返回 TMP; }

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


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

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

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

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

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

另外,我是否必须担心随时释放返回的变量或类列表变量,或者RIAA会为我处理这一切吗?

除非在某处new资源,否则无需delete资源。如果你确实使用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';
}

输出将指示柱线尚未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.