使用具有自己功能的 << 运算符来“覆盖” cout
Posted
技术标签:
【中文标题】使用具有自己功能的 << 运算符来“覆盖” cout【英文标题】:Use << operator with own function to "override" cout 【发布时间】:2020-05-15 12:26:31 【问题描述】:我知道有很多关于重载
我想做的是(我认为)完全不同(并且可能更简单)。 我有一个带有 2 个线程的控制台应用程序,都在控制台上编写。我想避免它们在控制台中相互碰撞,所以我使用互斥锁来防止一个线程在另一个线程输出时输出,所以我创建了函数:
void print(string s)
globals::console_mtx.lock();
cout << s << endl;
globals::console_mtx.unlock();
无论数据类型如何,我都希望它能够像这样使用:
int i=5;
print << "Some text" << i << endl;
谢谢
【问题讨论】:
【参考方案1】:这是你的想法吗?:
struct print_t ;
static const print_t print = print_t();
print_t& operator<<(print_t& p, const std::string& s)
globals::console_mtx.lock();
std::cout << s << endl;
globals::console_mtx.unlock();
return p;
注意。有大约十几种方法可以使它变得更好,例如将 print 作为具有唯一类型的函数等,以确保您不会遇到静态(取消)初始化顺序失败(如果可能,请避免在静态取消初始化中进行上述操作)。您可以使用 std 中cout
的定义作为备忘单。
【讨论】:
这似乎是我要找的。看到我不必为此费心上课,我松了一口气。谢谢你的帮助。但是,不确定静态去初始化是什么意思 哦,你有一个类,它只是空的 :) - 在 C++ 中你可能会在很多情况下遇到这样的类。print
现在是print_t
类型,技术上是static
全局变量,所以是在静态初始化的时候创建的(标准里面有规定,基本上,如果你有两个编译单元,顺序是不确定的之间)。因此,在初始化和销毁期间,使用它是不安全的,因为它可能已被销毁(尽管没有存储任何内容)。在main()
的开头和结尾之间使用是安全的。
@Raphael • 在C++ 中,关于静态和全局变量的构造顺序和破坏顺序没有太多保证。如果你只在main
开始之后和main
结束之前使用构造,你应该没问题。
我明白了。但是为什么我需要将 print 定义为 static ?
您想将其用作cout
。如果您不这样定义它,它将不会立即可用。也就是说,你总是可以在你的函数中写print_t print;
...【参考方案2】:
重载
print << "Some text" << i << endl;
实际上分别为“Some text”、i 和 endl 调用 print.operator
print << "Other text" << i+1 << endl;
那么你可能会得到:
"Some TextOther Text65\n\n"
处理它最简单的方法是先输出到字符串流,然后使用普通的打印函数打印被锁定的互斥锁保护的整个东西:
stringstream ss;
ss <<"Some text" << i << endl;
print(ss.str());
如果您坚持直接使用流,那么流仅在收到刷新指令时才实际写入来处理此类事情。 endl 自动刷新流,这是它与 "\n" 不同的方式之一。
然后您实现一个自定义 std::stringbuf 锁定互斥锁并在 sync() 上输出到控制台,然后为每个线程构造一个 ostream 以用作其个人打印输出流。
示例代码:
#include <iostream>
#include <sstream>
#include <mutex>
#include <thread>
#include <string>
// Increase risk of race condition if one can be triggered.
char slow_get_ch(char ch)
for (unsigned int i = 0; i < 10000; ++i)
for (unsigned int j = 0; j < 10000; ++j)
return ch;
class print_buf : public std::stringbuf
std::mutex& mtx_;
public:
print_buf(std::mutex& mtx)
:
mtx_(mtx)
protected:
int sync() final
std::unique_lock<std::mutex> lck(mtx_);
std::string val = this->str();
std::cout << val;
this->str("");
return 0;
;
void print_worker(std::ostream* print_stream_ptr,char ch)
std::ostream& print = *print_stream_ptr;
// Print 5 lines of 20 times ch.
for (unsigned int i = 0; i < 5; ++i)
for (unsigned int j = 0; j < 20; ++j)
print << slow_get_ch(ch);
print << std::endl;
int main()
std::mutex print_mutex;
print_buf buf1(print_mutex);
print_buf buf2(print_mutex);
print_buf buf3(print_mutex);
std::ostream p1(&buf1);
std::ostream p2(&buf2);
std::ostream p3(&buf3);
std::thread t1(print_worker, &p1, 'a');
std::thread t2(print_worker, &p2, 'b');
std::thread t3(print_worker, &p3, 'c');
t1.join();
t2.join();
t3.join();
return 0;
【讨论】:
这很复杂。我最终会使用你的 stringstream 解决方案以上是关于使用具有自己功能的 << 运算符来“覆盖” cout的主要内容,如果未能解决你的问题,请参考以下文章