用户定义的类和标准类之间有区别吗?
Is there a difference between user defined classes and std classes?
据我所知,构造函数/析构函数调用方式的唯一区别取决于实例化顺序。但是,"普通"用户类和 std 中的类之间还有其他区别吗?
假设我有一个名为myStackOverflow
的类,然后我实例化了这个类的一个对象。我在同一范围内还有一个类型std::thread
的对象。这些对象的构造函数或析构函数的调用方式是否有任何差异?
我问这个问题的主要原因是,根据C++标准(第 30.3.2.3 节),join()
不会在线程析构函数中调用。您可以在此处阅读原因。但是在这个关于堆栈溢出的答案中,提到将std::thread
包装在另一个类中,然后在这个新包装类的析构函数中调用join()
。我不明白这将如何解决任何问题。析构函数仍然是析构函数,在std::thread
的析构函数中调用join()
的危险仍然存在。
唯一有意义的方法是,这两种不同类型的析构函数的调用方式之间存在差异。
好的@Ali,让我们简要概述一些事情(术语)。
namespace std
- 是一个简单的命名空间,例如:
namespace my_namespace {
int my_integer;
};
它包含大量对程序员有用的类,由超强的程序员编写,并且,正如你所理解的,它应该尽可能灵活(后来的"语句 1"),因为不同的人有不同的需求。
当然,它遵守 c++ 标准的一般规则,因为它的内容也是如此。
现在让我们谈谈您想要的std::thread
。
它是一个表示单个执行线程的简单类。它允许您在"外空间"中执行你的函数,并与我们的抽象"外空间"保持联系,它还处理一些数据:
- _id - 线程 ID
- _handle - 秘密变量,它是与"外太空"通信的关键
- 当然,它会保留一些数据 关于执行状态(是否有任何实体现在在某处执行 钥匙引导我们到的"外太空")
如果您更详细地查找一些参考资料并记住我们的"声明 1",您会注意到以下信息:
- "
std::thread
对象也可能处于不表示任何线程的状态"> - "没有两个
std::thread
对象可以代表相同的执行线程;std::thread
不是CopyConstructible或CopyAssignable,尽管它是MoveConstructible和MoveAssignable。
现在您应该得出结论,std::thread
变量和执行实体是分开的,但尝试删除附加到执行实体std::thread
变量会引发异常。
但是,当实体完成执行时,std::thread
变量将保持活动状态,并且可以附加到任何其他实体。
对于这些需求,有以下方法:
join() // waits for a thread to finish its execution
// if it is attached to something, the code execution will not go futher until our entity finishes its execution.
detach() // permits the thread to execute independently from the thread handle
// detaches our std:: thread variable from executing entity, now our entity lives its own life. std::thread variable may be removed while the entity keeps alive
joinable() // checks whether the thread is joinable, i.e. potentially running in parallel context
// if thread is attached to something which is executing now, it returns true, otherwise false
这里有一些代码示例可以消除您的误解:
#include <iostream>
#include <thread>
#include <chrono>
using namespace::std;
void some_func1() {
cout << "some_func1 thread started " << endl;
this_thread::sleep_for(chrono::seconds(2));
cout << "some_func1 thread finished " << endl;
}
void some_func2() {
cout << "some_func2 thread started " << endl;
this_thread::sleep_for(chrono::seconds(2));
cout << "some_func2 thread finished " << endl;
}
int main() {
thread some_thread;
cout << "Is some_thread joinable: " << some_thread.joinable() << endl;
some_thread = thread(some_func1);
cout << "Is some_thread joinable: " << some_thread.joinable() << endl;
some_thread.detach();
cout << "Is some_thread joinable: " << some_thread.joinable() << endl;
this_thread::sleep_for(chrono::seconds(1));
some_thread = thread(some_func2);
cout << "Is some_thread joinable: " << some_thread.joinable() << endl;
some_thread.join();
cout << "Is some_thread joinable: " << some_thread.joinable() << endl;
}
// Output is:
// Is some_thread joinable: 0
// some_func1 thread started
// Is some_thread joinable: 1
// Is some_thread joinable: 0
// some_func2 thread started
// Is some_thread joinable: 1
// some_func1 thread finished
// some_func2 thread finished
// Is some_thread joinable: 0
// Press any key to continue . . .
如果你想确保你的实体在线程变量删除之前完成执行,你可以把它包装在另一个类中,并在析构函数中调用join()
,正如你提到的。
或者你也可以把它包装在另一个将在析构函数中调用detach()
。
这 2 种方式将防止您遭受大量暗恋。
#include <iostream>
#include <thread>
#include <chrono>
using namespace std;
typedef void Myfunc();
void some_func1() {
cout << "some_func1 thread started " << endl;
this_thread::sleep_for(chrono::seconds(2));
cout << "some_func1 thread finished " << endl;
}
void some_func2() {
cout << "some_func2 thread started " << endl;
this_thread::sleep_for(chrono::seconds(2));
cout << "some_func2 thread finished " << endl;
}
class ICareAboutThread {
std::thread thread_;
public:
ICareAboutThread( Myfunc f = nullptr) : thread_(f) {};
~ICareAboutThread() { join(); }
bool joinable() { return thread_.joinable();}
void join() { thread_.join();}
void detach() { thread_.detach();}
// other constructors : move , safe copying - if necessary;
};
class IDontCareAboutThread {
std::thread thread_;
public:
IDontCareAboutThread(Myfunc f = nullptr) : thread_(f) {};
~IDontCareAboutThread() { detach(); }
bool joinable() { return thread_.joinable(); }
void join() { thread_.join(); }
void detach() { thread_.detach(); }
// other constructors : move , safe copying - if necessary;
};
int main() {
ICareAboutThread i_care(some_func1);
this_thread::sleep_for(chrono::seconds(1));
IDontCareAboutThread i_dont_care(some_func2);
return 0;
}
// Output is:
// some_func1 thread started
// some_func2 thread started
// some_func1 thread finished
// Press any key to continue . . .
现在我希望它对您来说很清楚,如果您了解变量何时删除:D
- 在 typedef 内部使用 const 关键字和在 typedef 外部使用 const 关键字之间有区别吗?
- static_cast<unsigned>(签名)与标准::bit_cast<unsigned>(签名)之间有区别吗?
- 在调用函数时,ptr** 和 ptr*& 之间是否有区别,或者首选C++?
- 为什么 .cpp 文件和 .h 文件之间有区别?
- C++:调用运算符和调用其实现之间有区别吗
- 将全局声明为类声明语句的一部分与使用单独的语句声明全局之间是否有区别
- 用户定义的类和标准类之间有区别吗?
- 这两个数组之间有区别吗?
- 这些在C 中初始化C数组的方式之间有区别吗?
- vector.size()= 0和vector.empty()之间是否有区别
- 显式运算符 = 调用和 = 运算符之间是否有区别
- 这两种初始化成员变量的方法之间有区别吗?
- 在DirectX中,深度值中存储了哪些值?这在DX9和DX11之间有区别吗
- 如果"foo"是引用变量,[&foo]{ ... } 捕获和 [foo]{ ... } 捕获之间有区别吗?
- 在进行正向声明时,不命名参数和命名参数之间有区别吗
- 这两个fors之间有区别
- C++ 中的以下类似语句之间有区别吗?
- int x{} 之间有区别吗?和整数 x = 0;
- 具有公共成员而没有构造函数的结构和类之间的编译器是否有区别
- 在分配器中使用new函数和*alloc函数时,它们之间有区别吗