用户定义的类和std类之间有区别吗?

时间:2017-04-05 23:53:15

标签: c++ oop c++-standard-library

据我所知,调用构造函数/析构函数的方式唯一不同取决于实例化顺序。但是“标准”用户类和std中的类之间是否有任何其他区别?

假设我有一个名为myStackOverflow的类,然后我实例化了这个类的对象。我在同一范围内也有std::thread类型的对象。这些对象的构造函数或析构函数的调用方式是否存在差异?

我问这个问题的主要原因是根据C++ standard(第30.3.2.3节)join()未在线程析构函数中调用。您可以阅读here的原因。但是在关于stackoverflow的this回答中,提到将std::thread包装在另一个类中,然后在这个新包装类的析构函数中调用join()。我不明白这将如何解决任何问题。析构函数仍然是析构函数,在join()的析构函数中调用std::thread的危险仍然存在。

唯一有意义的方法是调用这两种不同类型的析构函数的方式不同。

1 个答案:

答案 0 :(得分:0)

好的@Ali,让我们简单概述一些事情(条款)。

namespace std - 是一个简单的命名空间,如:

namespace my_namespace {
    int my_integer;
};

其中包含大量有用的程序员类,由超级强大的程序员编写,并且,正如您所理解的那样,它应该尽可能灵活(后面的“声明1”),不同的人有不同的需求。

当然它遵循c ++标准的一般规则,因为它的内容也是如此。

现在让我们谈谈您想要的std::thread

它是一个代表a single thread of execution的简单类。它允许您在“外太空”中执行您的功能,并与我们的抽象“外太空”保持联系,它还处理一些数据:

  • _id - 主题ID
  • _handle - 秘密变量,是与“outerspace”进行沟通的关键
  • 当然它会保留一些数据 关于执行状态(任何实体现在在某处执行) 钥匙引导我们的“外太空”)

如果您查看some references更多详细信息并牢记我们的“声明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()的文件中。

这两种方式可以防止你受到大量粉碎。

#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