jav*_*ver 15 c++ boost iterator adapter c++11
我正在努力创造自己的boost::adaptors::transformed.
这是相关的提升代码.
这是它的用法(由LogicStuff的SO答案修改): -
C funcPointer(B& b){
//"funcPointer" is function convert from "B" to "C"
return instance-of-C
}
MyArray<B> test; //<-- any type, must already have begin() & end()
for(C c : test | boost::adaptor::transformed(funcPointer)) {
//... something ....
}
Run Code Online (Sandbox Code Playgroud)
结果将与: -
for(auto b : test) {
C c = funcPointer(b);
//... something ...
}
Run Code Online (Sandbox Code Playgroud)
我创造了CollectAdapter这样的目标boost::adaptor::transformed.
它在大多数常见情况下都能正常工作
有问题的部分是CollectAdapter- 我的图书馆的核心.
我不知道是否应该缓存collection_ by-pointer或by-value.
CollectAdapter封装底层collection_(例如指针std::vector<>): -
template<class COLLECTION,class ADAPTER>class CollectAdapter{
using CollectAdapterT=CollectAdapter<COLLECTION,ADAPTER>;
COLLECTION* collection_; //<---- #1 problem? should cache by value?
ADAPTER adapter_; //<---- = func1 (or func2)
public: CollectAdapter(COLLECTION& collection,ADAPTER adapter){
collection_=&collection;
adapter_=adapter;
}
public: auto begin(){
return IteratorAdapter<
decltype(std::declval<COLLECTION>().begin()),
decltype(adapter_)>
(collection_->begin(),adapter_);
}
public: auto end(){ ..... }
};
Run Code Online (Sandbox Code Playgroud)
IteratorAdapter(用于上面)封装底层迭代器,改变行为operator*: -
template<class ITERATORT,class ADAPTER>class IteratorAdapter : public ITERATORT {
ADAPTER adapter_;
public: IteratorAdapter(ITERATORT underlying,ADAPTER adapter) :
ITERATORT(underlying),
adapter_(adapter)
{ }
public: auto operator*(){
return adapter_(ITERATORT::operator*());
}
};
Run Code Online (Sandbox Code Playgroud)
CollectAdapterWidget(在下面使用)只是构造CollectAdapter-instance 的辅助类.
它可以像: -
int func1(int i){ return i+10; }
int main(){
std::vector<int> test; test.push_back(5);
for(auto b:CollectAdapterWidget::createAdapter(test,func1)){
//^ create "CollectAdapter<std::vector<int>,func1>" instance
//here, b=5+10=15
}
}
Run Code Online (Sandbox Code Playgroud)
上面的代码在大多数情况下都可以正常工作,除非COLLECTION是临时对象.
更具体地说,当我创建适配器的适配器适配器时,可能会发生悬挂指针.
int func1(int i){ return i+10; }
int func2(int i){ return i+100; }
template<class T> auto utilityAdapter(const T& t){
auto adapter1=CollectAdapterWidget::createAdapter(t,func1);
auto adapter12=CollectAdapterWidget::createAdapter(adapter1,func2);
//"adapter12.collection_" point to "adapter1"
return adapter12;
//end of scope, "adapter1" is deleted
//"adapter12.collection_" will be dangling pointer
}
int main(){
std::vector<int> test;
test.push_back(5);
for(auto b:utilityAdapter(test)){
std::cout<< b<<std::endl; //should 5+10+100 = 115
}
}
Run Code Online (Sandbox Code Playgroud)
这将导致运行时错误.这是悬空指针演示.
在实际使用中,如果界面更加精彩,例如使用|运算符,则更难以检测到错误: -
//inside "utilityAdapter(t)"
return t|func1; //OK!
return t|func1|func2; //dangling pointer
Run Code Online (Sandbox Code Playgroud)
如何改进我的库以修复此错误,同时保持性能和稳健性以及维持在同一水平附近?
换句话说,如何优雅地缓存数据或指针COLLECTION(可以是适配器或真实数据结构)?
或者,如果从头开始编码(比修改我的代码)更容易回答,那就去吧.:)
当前代码通过指针缓存.
解决方法的主要思想是按值缓存.
让适配器缓存值的COLLECTION.
这是主要的变化: -
COLLECTION collection_; //<------ #1
//changed from .... COLLECTION* collection_;
Run Code Online (Sandbox Code Playgroud)
坏处:-
std::vector)将被价值复制 - 浪费资源.std::vector直接使用时)我将创建2个版本的库 - AdapterValue和AdapterPointer.
我要创建相关的类(Widget,AdapterIterator,等)为好.
AdapterValue - 按价值计算.(专为utilityAdapter())AdapterPointer- 通过指针.(专为std::vector)坏处:-
我可以使用模板专业化来执行此操作: -
If( COLLECTION is an "CollectAdapter" ){ by value }
Else{ by pointer }
Run Code Online (Sandbox Code Playgroud)
坏处:-
很抱歉很长的帖子.
我个人会选择模板专业化——但是,不是专业化原始模板,而是一个嵌套类:
template<typename Collection, typename Adapter>
class CollectAdapter
{
template<typename C>
class ObjectKeeper // find some better name yourself...
{
C* object;
public:
C* operator*() { return object; };
C* operator->() { return object; };
};
template<typename C, typename A>
class ObjectKeeper <CollectAdapter<C, A>>
{
CollectAdapter<C, A> object;
public:
CollectAdapter<C, A>* operator*() { return &object; };
CollectAdapter<C, A>* operator->() { return &object; };
};
ObjectKeeper<Collection> keeper;
// now use *keeper or keeper-> wherever needed
};
Run Code Online (Sandbox Code Playgroud)
然后,外部类通过始终使用指针来覆盖这两种情况,而嵌套类则隐藏差异。
当然,不完整(您还需要添加适当的构造函数,例如,外部类和内部类),但它应该给您这个想法......
您甚至可以允许用户选择她/他是否想要复制:
template<typename Collection, typename Adapter, bool IsAlwaysCopy = false>
class CollectAdapter
{
template<typename C, bool IsCopy>
class ObjectWrapper // find some better name yourself...
{
C* object;
public:
C* operator*() { return object; };
C* operator->() { return object; };
};
template<typename C>
class ObjectWrapper<C, true>
{
C object;
public:
C* operator*() { return &object; };
C* operator->() { return &object; };
};
// avoiding code duplication...
template<typename C, bool IsCopy>
class ObjectKeeper : public ObjectWrapper<C, IsCopy>
{ };
template<typename C, typename A, bool IsCopy>
class ObjectKeeper <CollectAdapter<C, A>, IsCopy>
: public ObjectWrapper<CollectAdapter<C, A>, true>
{ };
ObjectKeeper<Collection> keeper;
};
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
428 次 |
| 最近记录: |