C ++严格别名规则和指向成员的指针

时间:2014-06-05 11:01:42

标签: c++ strict-aliasing member-pointers

以下代码在G ++中产生警告:

#include <iostream>
#include <cstdint>

template <typename T, typename P, typename Q>
Q T::*pointer_to(P T::*p, Q P::*q)
{
   typedef Q T::* output_ptr;
// warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
   size_t tmp = reinterpret_cast<const size_t&>(p) + reinterpret_cast<const size_t&>(q);
   return reinterpret_cast<const output_ptr&>(tmp);
}

struct A { int x; };
struct B { A a; };

int main()
{
   B b = B();
   b.*pointer_to(&B::a, &A::x) = 1;
   std::cout << b.a.x << std::endl;
}

无论如何它都能正常工作,但这让我很担心。

您有什么看法,这些&#34;子会员&#34;指针容易受到比普通成员指针更严格的别名问题?

1 个答案:

答案 0 :(得分:0)

我建议不要这样做。

您在评论中表示您尝试使用嵌套的std::bind,但是您使用的编译器版本存在问题。我不会诉诸黑客,而是将自己的重复指针滚动到成员类。

#include <iostream>
#include <cstdint>
#include <type_traits>
#include <utility>


template<typename Ptr1, typename... Rest>
class pointer_to_sub;

template<typename ObjType, typename Class>
class pointer_to_sub<ObjType Class::* >
{
  typedef ObjType Class::* ptr_type;

public:
  typedef ObjType value_type;
  typedef Class input_type;
  pointer_to_sub(ptr_type input)  : ptr(input)
  {

  }

  value_type& operator()(input_type& from) const
  {
    return from.*ptr;
  }

  value_type const& operator()(input_type const& from) const
  {
    return from.*ptr;
  }

  value_type& operator()(input_type* from) const
  {
    return from->*ptr;
  }

  value_type const& operator()(input_type const* from) const
  {
    return from->*ptr;
  }



  private:

  ptr_type ptr;
};


template<typename ObjType, typename Class, typename... Rest >
class pointer_to_sub<ObjType Class::*, Rest...> : private pointer_to_sub<Rest...>
{
  typedef ObjType Class::* ptr_type;
  typedef pointer_to_sub<Rest...> base_type;
public:
  typedef typename base_type::value_type value_type;
  typedef Class input_type;

  pointer_to_sub(ptr_type input, Rest... args) : base_type(args...), ptr(input)
  {

  } 

  value_type& operator()(input_type& from) const
  {
    return base_type::operator()(from.*ptr);
  }

  value_type const& operator()(input_type const& from) const
  {
    return base_type::operator()(from.*ptr);
  }


  value_type& operator()(input_type* from) const
  {
    return base_type::operator()(from->*ptr);
  }

  value_type const& operator()(input_type const* from) const
  {
    return base_type::operator()(from->*ptr);
  } 
private:
  ptr_type ptr;
};

template<typename T, typename... Args>
pointer_to_sub<T, Args...> make_pointer_to_sub(T t1, Args... args)
{
  return pointer_to_sub<T, Args...>(t1, args...);
}

上面基本上提供了一个make_pointer_to_sub,它获取了一个成员对象指针列表。它接受一个可转换为第一种类型的引用或指针作为其输入,然后依次取消引用每个指针。可以改进以接受unique_ptrshared_ptr,但这是为了以后。你可以使用它,如下所示。

struct A { int x; double y;};
struct B { A a; };

int main()
{
  auto ptr = make_pointer_to_sub(&B::a, &A::x);


   B b = B();
   ptr(b) = 1;
   // b.*pointer_to(&B::a, &A::x) = 1;

   std::cout << b.a.x << std::endl;
   ptr(&b) = 2;
   std::cout << b.a.x << std::endl;

}

如果需要,可以使用适当的参数将其分配给std::function