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,但如果你想要不同的行为,你可以使用不同的智能指针。
关键是当智能指针已经有那些隐式构造函数可以工作时,你不需要用户定义的构造函数。
我认为拥有用户定义的构造函数的唯一原因是:
你不能在一些低级代码中使用智能指针(我非常怀疑这种情况)。
您正在自己实现智能指针。
但是,在普通代码中,我看不出有任何理由使用用户定义的构造函数。
我在这里错过了什么吗?
我经常编写通过非常量引用获取参数的函数,但缺点是我无法传递 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在调用
临时的什么时候被销毁?
我很困惑为什么这些函数中的一个会出现硬错误,而另一个不会:
#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++ 中的未定义行为真的很难调试。是否有一个版本的 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++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)
会解决这个问题。
为什么范围很有用?与迭代器相比,我什么时候应该使用它们?
编辑:我知道范围比迭代器还有其他优点(链接、更好的方法等......)。然而,这些(我认为?)都可以用迭代器来完成,我不明白为什么需要引入一个全新的概念,比如范围。