类的模板化包装器函数(例如std::make_pair())是否被认为很慢
Are templated wrapper functions for classes (e.g. std::make_pair())` considered slow?
我在这个例子中使用std::make_pair()
,因为几乎任何C++程序员都应该熟悉它,但更普遍的是,我想知道它使用的模式。
我突然想到,尽管我喜欢std::make_pair()
的便利性,但它会为每个参数制作一个"额外"的副本,因为它会创建一对并按值返回。如果我用它插入STL容器,这意味着实际上每个参数总共复制了3次。。。我写了这个代码片段来说明(以及在不失去太多便利的情况下改进它的一些尝试):
#include <iostream>
#include <utility>
#include <list>
using namespace std;
// C++11 only:
#define MAKE_PAIR(a,b) pair<decltype(a),decltype(b)>((a),(b))
class A {
public:
A () { }
A (const A& a) {
cout << "tCopy constructor called" << endl;
}
};
int main()
{
list<pair<int,A> > l;
cout << "Using std::make_pair()" << endl;
l.push_back(make_pair(10,A()));
cout << "Using MAKE_PAIR()" << endl;
l.push_back(MAKE_PAIR(10,A()));
typedef pair<int, A> my_pair;
cout << "Using a typedef" << endl;
l.push_back(my_pair(10,A()));
}
产生输出:
Using std::make_pair()
Copy constructor called
Copy constructor called
Copy constructor called
Using MAKE_PAIR()
Copy constructor called
Copy constructor called
Using a typedef
Copy constructor called
Copy constructor called
我意识到这里还有一些其他副本可能会被消除(或者更确切地说,减少为指针/智能指针副本),例如,在这对副本中使用a*或智能指针,然后自己分配。
宏的想法(需要C++11)对我来说似乎很有趣,尽管我知道很多人不喜欢宏。typedef也很好用,但您必须为每组模板参数创建一个单独的typedef,因此它比每次显式指定模板参数更方便,它仍然不如包装器函数好。
我想知道有人真的因为这个原因而在实践中避开make_pair()
吗?C++/C++11是否提供了其他有趣的解决方案?
我喜欢在构造函数周围创建一个模板化函数包装器的想法,这样我们就可以推导出模板参数,但我并没有因此而对运行时产生影响
在我的编译器中,无论有没有优化,额外的复制构造函数都被优化掉了。
[10:53pm][wlynch@orange /tmp] c++ --version
Apple clang version 3.1 (tags/Apple/clang-318.0.45) (based on LLVM 3.1svn)
Target: x86_64-apple-darwin11.3.0
Thread model: posix
[10:54pm][wlynch@orange /tmp] c++ -O0 -std=gnu++11 foo.cc -o foo
[10:54pm][wlynch@orange /tmp] ./foo
Using std::make_pair()
Copy constructor called
Copy constructor called
Using MAKE_PAIR()
Copy constructor called
Copy constructor called
Using a typedef
Copy constructor called
Copy constructor called
如果我添加参数-fno-elide-constructors
,那么我们会看到额外的构造函数。
[10:57pm][wlynch@orange /tmp] c++ -std=gnu++11 -fno-elide-constructors foo.cc -o foo
[10:57pm][wlynch@orange /tmp] ./foo
Using std::make_pair()
Copy constructor called
Copy constructor called
Copy constructor called
Copy constructor called
Using MAKE_PAIR()
Copy constructor called
Copy constructor called
Using a typedef
Copy constructor called
Copy constructor called
C++规范对跳过2003规范的[class.copy.15]中的复制构造函数有这样的看法
当满足某些条件时,允许实现省略类对象的复制构造,即使该对象的复制构造函数和/或析构函数有副作用。在这种情况下,实现将省略的复制操作的源和目标视为引用同一对象的两种不同方式,并且该对象的销毁发生在两个对象在没有优化的情况下被销毁的较晚时间。)在以下情况下允许省略复制操作(可以组合以消除多个副本):
- 在具有类返回类型的函数中的return语句中,当表达式是与函数返回类型具有相同cv不合格类型的非易失性自动对象的名称时,可以通过将自动对象直接构造到函数的返回值中来省略复制操作
- 当尚未绑定到引用(12.2)的临时类对象将被复制到具有相同cv不合格类型的类对象时,可以通过将临时对象直接构造到被省略的复制的目标中来省略复制操作
- 是否需要删除包含对象的"pair"?
- VS Code "command":"make"与终端窗口中的命令行"make"不同
- 在我的代码中,获得最大的Pair Wise产品C++和输出并不总是正确的
- 为什么大多数 pair 实现默认不使用压缩(空基优化)?
- 使用 make 编译 MPI,几个命名空间错误,例如"错误:未知类型名称'使用'?
- make 命令如何避免重新编译未更改的源文件?
- 对 pair<pair<int,int>pair<int,int unordered_map进行哈希处理>>
- MAKE:找不到包含的用户定义的头文件?
- 对的排序向量 (std::vector<pair<int, int>>) 按对的第一个元素搜索并更新第二个元素值
- 'make check' GLIBC 运行时的链接问题
- 删除字符串中具有相同值的任何相邻字母"pair"
- Qt5 [make -snap] 无法正确编译:进程"/usr/bin/snap"代码 1 退出
- 当我尝试定义这个向量时<pair<int , pair<int, int> > > vp(n)
- mingw32-make 使用"MinGW Makefiles"生成器跟踪 CMAKE 无法将可执行文件链接到对象库
- 如何从map<pair<string,int>,pair<string,Array>>中迭代和查找?
- make 命令创建 .file,但不创建应用程序文件
- 如何摆脱导入的 make 项目中的 Eclipse 索引器"Type std::... could not be resolved"错误
- Qt Creator 在执行步骤 "make" 时出现编译错误,-fno-stack-limit
- 如何使用MySQL Connector and Make设置C++项目
- 使用 make 将对象文件放在特定目录中