I don’t want to see another “using namespace xxx;” in a header file ever again

There, I’ve said it. No tiptoeing around.

As a senior developer/team lead, I get involved in hiring new team members and in certain cases also help out other teams with interviewing people. As part of the interview process, candidates are usually asked to write code, so I review a lot of code submissions. One trend I noticed with recent C++ code submissions is that the first like I
encounter in *any* header file is

using namespace std;

If we happen to review the code submission using our code review system (a practice I’d highly recommend), the above line is usually followed by a comment along the lines of “Timo is not going to like this”. And they’re right, I don’t.

So, why am I convinced that this is really, really bad practice despite a ton of (maybe not very good) C++ textbooks containing the above piece of code verbatim? Let’s for a moment review what the above statement does. Basically, it pulls the whole contents of the namespace “std” (or any other namespace that the author used the using statement
for) into the current namespace with no exceptions. And I mean *anything*, not just the one or two classes/typedefs/templates you’re trying to use. Now, the reason that namespaces were introduced in the first place is to improve modularization and reduce the chances of naming conflicts. It basically allows you to write the following
code and ensure that the compiler picks the correct implementations:

std::vector<std::string> names;
my_cool_reimplementation::vector<our_internal_stuff::string> othernames;

Now assume that we’re trying to reduce the amount of typing and put the above using statement in the code (or worse, use both namespaces) and write the following:

vector<string> names;
vector<our_internal_stuff::string> othernames;

If the author of the code is very lucky, the correct implementation of vector will be picked, at least initially. And some time down the road, you’ll encounter strange compiler errors. Good luck finding those – I’ve been in situations where it took days to track down this sort of problem. That’s a heck of a timewaster that you just got for saving to
type five characters.

Also, if you’re putting the using statement into the header file, you’re aggravating the problem because the conflicts you will run into sooner or later will be in a module far, far away for no apparent reason until you find out that three layers down, one include file happens to include the file that contains the using directive and suddenly polluted
whichever namespace the file contained with the whole contents of namespace std.

So why is using namespace std; found in so many textbooks? My theory is that it does help with the layout of the book and it reduces visual clutter. In a dead tree book, you only have very limited amounts of space so you need to make the most of it, plus the code examples are generally fairly trivial. That, and the various namespace qualifications
introduce a lot of visual clutter that doesn’t help with getting the author’s point across in the context of a textbook. Neither of these really hold true when it comes to production code in the age of 24″ monitors and text editors that can handle more than 60-80 characters per line (try it, it works!). So, don’t do it.

So, what can you do if you absolutely, positively have to use a using declaration in a header file? There are other ways to reduce the impact of having to do so – you can use one of them, or all of them in various combinations.

First, you can simply use a typedef. I would suggest that this is good practise anyway even if I don’t always follow my own advice. Using a typedef actually has two benefits – it makes a typename more readable and it documents the author’s intent if a well chosen name has been used. Compare the following declarations:

std::map<std::string, long> clientLocations;
typedef std::map<std::string, long> ClientNameToZip;
ClientNameToZip clientLocations;

The second declaration – even though it spans two lines – is much more self documenting than the first one and it gets rid of the namespace fuzz at the same time.

Another option is to limit the scope of the using statement in two ways – only “using” the names of the symbols you need to use, for example:

using std::string;

Again, just throwing this statement into a header file is almost as bad an idea as putting in “using namespace”, so you should limit its visibility by making use of C++ scopes to ensure that your using declaration really only affects the parts of the code that need to see your using declaration in the first place. For example, you could limit
the scope to a class declaration:

namespace bar
{
  struct zzz
  {
    …
  };
}
class foo
{
  using namespace bar;
  zzz m_snooze; // Pulls in bar::zzz 
};

Or you can limit the scope of a using directive to a single function, for example like this:

void temp()
{
  using namespace std;
  string test = "fooBar";
}

In either case, you are restricting the visibility of a using directive to the part of the code that requires it rather than throwing it right into everybody’s way. The bigger your projects get, the more important it is to ensure proper modularization and minimize unintended harmful side effects.

在使用PyQt5创建图形用户界面时,确保应用程序在运行过程中不会因子进程而卡顿,你可以采取以下几个策略: 1. **异步执行**: 使用`QThread`或者`pyqt5.QtConcurrent`模块的`run`, `execute`或`mapped`函数将子进程的任务放到另一个线程中执行。这样,主线程仍然负责维护UI的响应性和交互,而子进程在后台独立运行。 ```python from PyQt5.QtCore import QRunnable, QThreadPool, pyqtSlot from PyQt5.QtWidgets import QApplication from PyQt5.QtWidgets import QMainWindow import subprocess class Worker(QRunnable): def __init__(self, command): super().__init__() self.command = command @pyqtSlot() def run(self): proc = subprocess.Popen(self.command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # 在子进程中执行任务... # ... app = QApplication([]) main_window = QMainWindow() pool = QThreadPool() worker = Worker(['your_command']) pool.start(worker) # 主线程继续操作UI... ``` 2. **回调和信号槽**: 结合`QObject.signals`功能,创建一个连接到子进程完成或错误事件的信号槽,一旦子进程结束,就会更新UI。 ```python from PyQt5.QtCore import pyqtSignal, QObject import subprocess class ProcessHandler(QObject): finished = pyqtSignal(object) # 定义一个信号 def run_process(self, command): proc = subprocess.Popen(command, ...) proc.wait() if proc.returncode == 0: self.finished.emit(proc.stdout) # 发送成功信号 else: self.error_message.emit('Subprocess failed') # 在主窗口中接收信号并更新UI handler = ProcessHandler() handler.finished.connect(self.update_ui_on_completion) handler.run_process(['your_command']) ``` 3. **分块处理**(适用于大量数据处理): 对于大数据处理,可以考虑使用`QFuture`,它允许你分块处理结果,而不是一次性等待整个过程完成。 ```python from PyQt5.QtCore import QFuture, qDebug, Qt from PyQt5.QtWidgets import QApplication from PyQt5.QtConcurrent import run, Future def worker_function(data): # 在子进程中处理数据... return result data = [...] # 大量数据 future = run(worker_function, data, Qt.QThreadPool.globalInstance().maximumThreadCount()) for result in future.waitForFinished(): # 持续获取结果并更新UI # 更新UI部分... ``` 记住,无论哪种方法,都要确保关闭子进程资源(如文件描述符、线程等),以防止内存泄漏。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值