Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/154.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 创建用于重写迭代器的运算符*()的库-风险悬空指针_C++_C++11_Boost_Iterator_Adapter - Fatal编程技术网

C++ 创建用于重写迭代器的运算符*()的库-风险悬空指针

C++ 创建用于重写迭代器的运算符*()的库-风险悬空指针,c++,c++11,boost,iterator,adapter,C++,C++11,Boost,Iterator,Adapter,我正在努力创造我自己的 这里是相关的 以下是它的用法(修改自):- 我的尝试 我创建了CollectAdapter,旨在像boost::adapter::transformed 在大多数情况下,它都可以正常工作 这是完整的和完整的。(与以下代码相同) 有问题的部分是CollectAdapter——我的库的核心。 我不知道是应该按指针缓存集合还是按值缓存 CollectAdapter封装底层集合(例如指向std::vector)的指针:- CollectAdapterWidget(下面使用)只是一

我正在努力创造我自己的

这里是相关的

以下是它的用法(修改自):-

我的尝试 我创建了
CollectAdapter
,旨在像
boost::adapter::transformed

在大多数情况下,它都可以正常工作

这是完整的和完整的。(与以下代码相同)

有问题的部分是
CollectAdapter
——我的库的核心。
我不知道是应该按指针缓存
集合
还是按值缓存

CollectAdapter封装底层
集合
(例如指向
std::vector
)的指针:-

CollectAdapterWidget
(下面使用)只是一个帮助器类,用于构造
CollectAdapter
-实例

它可以像这样使用:-

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
    }
}  
这将导致运行时错误。这是

在实际使用中,如果界面更棒,例如使用
|
操作符,那么bug将更难被检测到:-

//inside "utilityAdapter(t)"
return t|func1;        //OK!
return t|func1|func2;  //dangling pointer
问题: 如何改进我的库以修复此错误,同时保持性能&健壮性&可维护性接近相同水平

换句话说,如何优雅地缓存
集合
(可以是适配器真实数据结构)的数据或指针

或者,如果从头开始编写代码(比修改代码)更容易回答问题,那就去做吧。:)

我的变通办法 当前代码通过指针缓存
解决方法的主要思想是按值缓存

解决方案1(始终“按值”) 让适配器缓存
集合的

主要变化如下:-

COLLECTION collection_;    //<------ #1 
//changed from   .... COLLECTION* collection_;
缺点:-

  • 许多适配器类之间没有很好的协作。
    它们必须相互识别:已识别=应按值缓存

很抱歉发了这么长的邮件

我个人会选择模板专业化–但是,不是专门化原始模板,而是一个嵌套类:

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
};
模板
类集合适配器
{
模板
类ObjectKeeper//自己找一个更好的名字。。。
{
C*对象;
公众:
C*运算符*(){return object;};
C*运算符->(){return object;};
};
模板
类对象管理员
{
采集适配器对象;
公众:
CollectAdapter*运算符*(){return&object;};
CollectAdapter*运算符->(){return&object;};
};
对象管理员;
//现在在需要的地方使用*keeper或keeper->
};
然后,外部类通过始终使用指针来覆盖这两种情况,而嵌套类则隐藏差异

当然,是不完整的(例如,您还需要向外部类和内部类添加适当的构造函数),但它应该让您了解

您甚至可以允许用户选择是否要复制:

模板
类集合适配器
{
模板
类ObjectWrapper//自己找到更好的名称。。。
{
C*对象;
公众:
C*运算符*(){return object;};
C*运算符->(){return object;};
};
模板
类对象包装器
{
C对象;
公众:
C*运算符*(){return&object;};
C*运算符->(){return&object;};
};
//避免代码重复。。。
模板
类ObjectKeeper:PublicObjectWrapper
{ };
模板
类对象管理员
:公共对象包装器
{ };
对象管理员;
};
在my中,如果集合是右值,则存储集合的值;如果集合是左值,则存储引用。在这里也可以这样做:为右值和左值重载
操作符|

template<typename Collection,typename Filter>
auto operator|(Collection&& collection,Filter filter){
   return create_adapter_for_rvalue_collection(collection,filter);
}
template<typename Collection,typename Filter>
auto operator|(Collection const& collection,Filter filter){
   return create_adapter_for_const_lvalue_collection(collection,filter);
}
template<typename Collection,typename Filter>
auto operator|(Collection & collection,Filter filter){
   return create_adapter_for_non_const_lvalue_collection(collection,filter);
}
模板
自动运算符|(收集和收集,过滤器){
返回为右值集合(集合、筛选器)创建适配器;
}
模板
自动运算符|(采集常量和采集、过滤器){
返回create_adapter_for_const_lvalue_collection(collection,filter);
}
模板
自动操作员|(收集和收集,过滤器){
返回为非常量左值集合(集合、筛选器)创建适配器;
}

在存储(因此使用)适配器时,如果不查看您的代码,所有增压范围适配器都有一个共同的陷阱,即悬挂引用。我经常烧伤自己,所以我采取了避免范围适配器的措施,除非非适配器代码绝对无效unwieldy@sehe这是非常有用的。谢谢。这里有一个参考案例,很高兴知道我的目标是做一些比boost更好的事情,尽管这可能不切实际或非常困难。:)我建议看看Niebler的Range-V3方案(公开实施)看起来您的
ObjectWrapper
std::reference\u wrapper
非常相似:我可以通过专门研究
std::reference\u wrapper
看到一个版本,所以OP的代码应该是
autoadapter1=collectoradapterwidget::createAdapter(std::ref(t),func1)
自动适配器12=CollectAdapterWidget::createAdapter(适配器1,函数2)。这需要通过引用(典型情况)使用
std::ref
。也许它可以翻转,所以ref是默认值,但value是可选的?按照这些思路,可能(但更危险的是)有一个版本使用存储引用的
const T&
的第一个参数,另一个版本使用存储引用的
T&
。然后
createAdapter(createAdapter(t,func1),func2)
将拥有内部适配器,但内部适配器将只具有对t的引用。我喜欢
&
部分
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
    }
}
//inside "utilityAdapter(t)"
return t|func1;        //OK!
return t|func1|func2;  //dangling pointer
COLLECTION collection_;    //<------ #1 
//changed from   .... COLLECTION* collection_;
If( COLLECTION is an "CollectAdapter" ){ by value }  
Else{ by pointer }    
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
};
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;
};
template<typename Collection,typename Filter>
auto operator|(Collection&& collection,Filter filter){
   return create_adapter_for_rvalue_collection(collection,filter);
}
template<typename Collection,typename Filter>
auto operator|(Collection const& collection,Filter filter){
   return create_adapter_for_const_lvalue_collection(collection,filter);
}
template<typename Collection,typename Filter>
auto operator|(Collection & collection,Filter filter){
   return create_adapter_for_non_const_lvalue_collection(collection,filter);
}