当前位置: 首页 > 工具软件 > EASTL > 使用案例 >

奇怪的EASTL编译warning问题

叶俊郎
2023-12-01
查了一个坑爹的EASTL编译问题,原来的文件是这样的:

eastl::copy(behaviors.begin(), behaviors.end(), eastl::back_inserter(m_kBehaviors));
 
把std::back_inserter替换成eastl::back_inserter,编译器报出一个warning,由于我们treat warning as error,必须解决。检查过程却是漫长而曲折。
 
出错信息是:
 
warning C4512: 'eastl::back_insert_iterator<Container>' : assignment operator could not be generated
 
排查步骤:
1.  把eastl相关代码剥离检查,没有发现有什么问题。
                 template <typename Container>
                 class back_insert_iterator : public eastl::iterator <EASTL_ITC_NS:: output_iterator_tag, void , void, void, void >
                {
                 public:
                                 typedef Container                            container_type;
                                 typedef typename Container:: const_reference const_reference ;
 
                 protected:
                                 Container& container ;
 
                 public:
                                 explicit back_insert_iterator (Container& x)
                                                : container(x ) { }
 
                                 back_insert_iterator& operator =(const_reference value)
                                                { container.push_back (value); return *this ; }
 
                                 back_insert_iterator& operator *()
                                                { return *this ; }
 
                                 back_insert_iterator& operator ++()
                                                { return *this ; } // This is by design.
 
                                 back_insert_iterator operator ++(int)
                                                { return *this ; } // This is by design.
                };
                 template <typename Container>
                 back_insert_iterator<Container > back_inserter( Container& x )
                {
                                 return back_insert_iterator <Container>( x);
                }
 
2. 把相应代码copy到CPP代码里面,放进自己的namespace test,然后再使用新版本的test::back_inserter,居然就没有warning了。两者代码完全一样。
eastl::copy(behaviors.begin(), behaviors.end(), test::back_inserter(m_kBehaviors));
 
3. 怀疑是全局的compiler状态影响了编译结果,既然是 warning c4512,是不是我们在头文件里面定义过disable这个warning,所以导致test::back_inserter编译时刻的状态和eastl::back_inserter的编译状态不同呢?于是在test::back_inserter后面,测试test::back_inserter的前面,加上了#pragma warning(default: 4512),恢复编译器的warning 4512状态。我的原意是希望在编译到test::back_inserter(m_kBehavior)的时候使用新的编译warning状态,这样就会报错了。 居然还是不报错。
 
4. 想了一下,觉得template是在编译到test::back_inserter(m_kBehavior)的时候报错,但其实在之前编译模版定义的时候已经有disable warning 4512的状态了。所以这个#pragma warning(default: 4512)应该加在namespace test之前,这样test::back_inserter模版定义带有disable warning 的buff。试了一下果然有效,又开始报出warning了。
 
结论1: #pragma的状态,在模版定义时生效,而不是在模版实例化时生效。想要改变模版中的编译状态,就要在定义模版前pragma
想想也符合逻辑。。。我的猜想是,一般实例化template的时候还是需要回去看template的定义的,而此时的编译器状态要被恢复到那时候的状态了,合情合理

5. 感觉问题搞定了,就是因为C4512被disable了,所以test::back_inserter不会报错,而编译eastl::back_inserter的时候,这个warning还没有被disable,所以报出warning
 
6. 突然想到,为啥std::back_inserter一直不报warning呢?连忙开了一个空项目,把eastl::back_inserter和std::back_inserter代码全部都抽出来放进去,再做试验。std怎么都不错,eastl就会出问题。如果加上#pragma warning ( disable: 4512),eastl也会shut up了。中间还绕了一些弯路,怀疑std的stl是不是偷偷在header里面disable了warning,事实证明我想多了。
 
7. 这不是问题的关键,关键是这个warning本身,一定是std和eastl实现上有一些不同。仔细比较两者的代码,发现了关键的不同点:
    为了实现back_inserter功能,两者都需要保证可以访问原有容器,存放原有容器的方法有不同。 EASTL里面用了reference,STD stl里面用了Pointer。
    而编译器会为这个类隐式产生拷贝构造函数assignment operator,在EASTL里面由于是引用,所以编译器无法产生拷贝构造函数,warning里面抱怨的就是这个情况。见Effective C++, Item 5.
    From Effective C++,  Item 5
     如果你自己不声明一个拷贝构造函数,一个拷贝赋值运算符和一个析构函数,编译器就会为这些东西声明一个它自己的版本。而且,如果你自己连一个构造函数都没有声明,编译器就会为你声明一个缺省构造函数。
     面对这个难题,c++ 拒绝编译器产生代码。如果你希望一个包含引用成员的类支持赋值,你必须自己定义拷贝赋值运算符
 
结论2:EASTL的back_inserter_iterator实现不够好,需要把引用换成指针避免warning
 
8. 额外问题:问题已经解决。但是引申出来的问题是,back_insert_iterator里面不是已经有operator=了吗,为啥编译器还要生成一个operator=,以至于报出warning。简单研究了一下,答案很简单,operator=的prototype不同。正规的operator=应该是这样的
back_insert_iterator < Container>& operator =(const back_insert_iteratorvalue )
但现有的类里面是这样的,根本不是同一个东西。。。
back_insert_iterator & operator =( const_reference value )
 
总结:查这个问题走了很多的弯路,总是怀疑是自己的问题,不从EASTL本身去查原因,去查编译器状态,导致开始走错了方向。

转载于:https://www.cnblogs.com/gamedev/archive/2012/10/02/2710190.html

 类似资料: