-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
对construct的可变参数模板进行更新 #124
base: master
Are you sure you want to change the base?
Conversation
(新手观点,大佬轻喷) 目前版本的construct的可变参数模板版本并不能有效地让自定义类通过construct来创建对象,如: 对于如下代码: ~~~ #include<iostream> #include"allocator.h" using namespace std; class A{ public: A(int a):m(a),n(0.0){ cout<<"int constructor"<<endl; } A(int a,double b):m(a),n(b){ cout<<"int and double constructor"<<endl; } int m; double n; }; int main(){ mstl::allocator<A> a; A* p1=a.allocate(10); a.construct(p1,10);//construct的模板参数包匹配的类型为int,相当于construct(A*,int && args) a.construct(p1,10,1.0);//相当于construct(A*,int &&,double &&),此时无法调用自己写的forward a.deallocate(p1); return 0; } ~~~ 如果construct.h中存在 template<typename T,typename ...Args> void construct(T* ,Args && ...args),那么会导致a.construct(p1,10)无法正确匹配到util.h中的construct(Ty1 *,const Ty2&value),a.construct(p1,10,1.0)会报no matching function的错误 如果将上述代码从construct.h中删掉,那么第20行代码会调用A(int)构造函数,打印出"int constructor" 第21行代码则会因为没有对应版本的forward\<T\>而报错 但是std::allocator是可以实现上述功能的: ~~~ #include<iostream> #include"allocator.h" using namespace std; class A{ public: A(const int& a):m(a),n(0.0){ cout<<"int constructor"<<endl; } A(int && a):m(mstl::move(a)),n(0.0){ cout<<"int move constructor"<<endl; } A(const int& a,const double &b):m(a),n(b){ cout<<"int and double constructor"<<endl; } int m; double n; }; int main(){ allocator<A> a; A* p1=a.allocate(10); int b=10; a.construct(p1,20);//打印"int constructor" a.construct(p1,10,1.0);//打印"int and double constructor" cout<<p1->m<<endl;//10 a.deallocate(p1,10); return 0; } ~~~ 通过调试,发现上述代码在执行到construct(p1,10,0.1)时,跳转到了new_allocator.h里的construct可变参数模板: ![image-20230114233907408](C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20230114233907408.png) 解决方法: 在/allocator.h的allocator结构体内部的construct()直接使用::new分配空间和调用对象的构造函数, ~~~ template<class T> template<typename Other,typename ... Args> void allocator<T>::construct(Other* p,Args && ... args){ ::new ((void*)p) Other(mstl::forward<Args>(args)...); } ~~~ 事实上,无需提供三个版本的construct()(通过调用util.h里的重载的construct函数),在allocator里仅需一个上述的construct可变参数模板,也可以满足很多情况的使用: ~~~ ... int main(){ mstl::allocator<A> a;/《?》 A* p1=a.allocate(10); a.construct(p1,10);//int move constructor a.construct(p1,10,1.0);//int and double constructor int n1=10; double n2=2.0; a.construct(p1,n1,n2);//int and double constructor a.deallocate(p1,10); return 0; } 执行结果如下: int move constructor int and double constructor int and double constructor ~~~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
可以只留下这个修改过的 construct
重载,把另外几个重载移除吗?参考 C++11 的设计。
(题外话: MyTinySTL 还没有加入 allocator_traits
,如果有的话 allocator
就不需要 construct
成员了。)
forward通过引用折叠实现了实参类型的完美转发,所以const T &和T &&类型的重载可以移除,指针类型T *的重载不太确定(关于指针实参是否存在类似于引用折叠的机制不是很清楚),但是vscode源码里的new_allocator.h只有这一个可变参数模板的版本 |
(新手观点,大佬轻喷)
目前版本的construct的可变参数模板版本并不能有效地让自定义类通过construct来创建对象,如: 对于如下代码:
如果construct.h中存在
template<typename T,typename ...Args>
void construct(T* ,Args && ...args),那么会导致a.construct(p1,10)无法正确匹配到util.h中的construct(Ty1 *,const Ty2&value),a.construct(p1,10,1.0)会报no matching function的错误 如果将上述代码从construct.h中删掉,那么第20行代码会调用A(int)构造函数,打印出"int constructor" 第21行代码则会因为没有对应版本的forward<T>而报错
但是std::allocator是可以实现上述功能的:
通过调试,发现上述代码在执行到construct(p1,10,0.1)时,跳转到了new_allocator.h里的construct可变参数模板:
解决方法:
在/allocator.h的allocator结构体内部的construct()直接使用::new分配空间和调用对象的构造函数,
事实上,无需提供三个版本的construct()(通过调用util.h里的重载的construct函数),在allocator里仅需一个上述的construct可变参数模板,也可以满足很多情况的使用: