小编Som*_*mer的帖子

5 法则(对于构造函数和析构函数)是否过时了?

5 规则指出,如果一个类有一个用户声明的析构函数、复制构造函数、复制赋值构造函数、移动构造函数或移动赋值构造函数,那么它必须有其他 4 个。

但今天我突然明白了:你什么时候需要用户定义的析构函数、复制构造函数、复制赋值构造函数、移动构造函数或移动赋值构造函数?

在我的理解中,隐式构造函数/析构函数适用于聚合数据结构。但是,管理资源的类需要用户定义的构造函数/析构函数。

但是,不能将所有资源管理类都使用智能指针转换为聚合数据结构吗?

例子:

// RAII Class which allocates memory on the heap.
class ResourceManager {
    Resource* resource;
    ResourceManager() {resource = new Resource;}
    // In this class you need all the destructors/ copy ctor/ move ctor etc...
    // I haven't written them as they are trivial to implement
};
Run Code Online (Sandbox Code Playgroud)

对比

class ResourceManager {
    std::unique_ptr<Resource> resource;
};
Run Code Online (Sandbox Code Playgroud)

现在示例 2 的行为与示例 1 完全相同,但所有隐式构造函数都可以工作。

当然,你不能 copy ResourceManager,但如果你想要不同的行为,你可以使用不同的智能指针。

关键是当智能指针已经有那些隐式构造函数可以工作时,你不需要用户定义的构造函数。

我认为拥有用户定义的构造函数的唯一原因是:

  1. 你不能在一些低级代码中使用智能指针(我非常怀疑这种情况)。

  2. 您正在自己实现智能指针。

但是,在普通代码中,我看不出有任何理由使用用户定义的构造函数。

我在这里错过了什么吗?

c++ smart-pointers raii resource-management

40
推荐指数
5
解决办法
4031
查看次数

通过引用传递 r 值?

我经常编写通过非常量引用获取参数的函数,但缺点是我无法传递 r 值。

我的一位同事向我展示了这段据说可以解决问题的代码:

#include <iostream>

// example function
int f(int& x) {
    x += 5;
    return x;
}

// is this undefined behaviour?
auto& to_l_value(auto&& x) {
    return x;
}

int main () {
    auto y = f(to_l_value(5)); // usage example
    std::cout << y; // 10
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这是由于悬空引用而导致的未定义行为吗?(5之前被摧毁了f在调用

临时的什么时候被销毁?

c++ language-lawyer c++20

6
推荐指数
1
解决办法
206
查看次数

C++ 中的表达式 SFINAE 和硬错误

我很困惑为什么这些函数中的一个会出现硬错误,而另一个不会:

#include <utility>

template <typename ...Args>
auto ffExists1()
-> decltype(ff(std::declval<Args>()...)); // Attempts to see
    // whether you can call ff (which is not defined or declared)
    // with arguments of type Args... This works fine.

template <typename ...Args>
auto ffExists2() -> decltype(&ff); // Gives me a hard error : ff not defined
Run Code Online (Sandbox Code Playgroud)

这是为什么?另外,我该如何ffExists2工作?使用指向函数的指针可以让我确定ffwhile的确切签名,ffExists1只知道我是否可以ff使用类型的参数进行调用Args...

编辑:这是一个ffExists2依赖于模板的版本,导致相同的结果:

#include <utility>

template <typename ...Args>
auto ffExists() -> decltype(ff(std::declval<Args>()...)); //Fine

template <typename ... Args> …
Run Code Online (Sandbox Code Playgroud)

c++ sfinae c++20

4
推荐指数
1
解决办法
98
查看次数

是否有没有未定义行为的安全版本的 C++?

C++ 中的未定义行为真的很难调试。是否有一个版本的 C++ 和标准库不包含任何未定义的行为而是抛出异常?我知道这将是一个性能杀手,但我只打算在我在调试模式下编程、调试和编译时使用这个版本,并不真正关心性能。理想情况下,此版本是可移植的,您可以轻松打开/关闭未定义的行为检查。

例如,你可以实现一个像这样的安全指针类(只检查空指针,实际上如果它指向一个有效的内存块,则不会):

template <typename T>
class MySafePointer {
     T* value;
public:
      auto operator-> () {
          #ifndef DEBUG_MODE
          assert(value && "Trying to dereference a null pointer");          
          #endif
          return value;
      }
      /* Other Stuff*/

};
Run Code Online (Sandbox Code Playgroud)

在这里,用户只需要#undef DEBUG_MODE在您想恢复性能时才需要。

是否有 C++ 的库/安全版本可以做到这一点?

编辑:更改了上面的代码,使其实际上更有意义并且不会抛出异常但断言值非空。问题只是一个描述性错误消息与崩溃的问题......

c++ undefined-behavior

3
推荐指数
2
解决办法
192
查看次数

c++20 范围的意义是什么?

我很难理解 c++20 范围与老式迭代器相比增加了什么。是的,我想不再需要使用beginand end,而是简单的重载,例如:

namespace std {
    template <typename Container>
    auto transform(Container&& container, auto&&... args) requires ( requires {container.begin(); container.end(); }) {
         return transform(container.begin(), container.end(), args...);
    }
}
Run Code Online (Sandbox Code Playgroud)

会解决这个问题。

为什么范围很有用?与迭代器相比,我什么时候应该使用它们?

编辑:我知道范围比迭代器还有其他优点(链接、更好的方法等......)。然而,这些(我认为?)都可以用迭代器来完成,我不明白为什么需要引入一个全新的概念,比如范围。

c++ iterator c++20 std-ranges

3
推荐指数
1
解决办法
2304
查看次数