C++ 我应该避免在这里使用指针吗?

C++ 我应该避免在这里使用指针吗?,c++,dictionary,pointers,std,stdmap,C++,Dictionary,Pointers,Std,Stdmap,我有一个简单的代码: std::vector<std::map<double,double>> v; //populate v //we know each map already has correct key order (enforced by c++) //but i also want to make sure the different maps have correct key order //this is how I do it using a poi

我有一个简单的代码:

std::vector<std::map<double,double>> v;
//populate v

//we know each map already has correct key order (enforced by c++)
//but i also want to make sure the different maps have correct key order
//this is how I do it using a pointer:

const double *last_key = nullptr;
for (const auto &map : v)
{
  if (map.size() > 0) //ignore empty maps
  {
    if (last_key)
    {
      const auto &new_key = map.cbegin()->first;
      if (!(*last_key < new_key))
        throw std::runtime_error("invalid key order");
    }
    last_key = &(--map.cend())->first;
  }
}
这是可行的,但它要求密钥是默认可构造的,并且它涉及到不必要的密钥复制(不同于
double
的密钥类型的问题)。

好的,既然我现在(认为我)理解了您的代码,下面是我的看法:

auto iter = v.begin();
auto end = v.end();
while (iter != end && iter->empty())
  ++iter;
if (iter != end)
{
  while (true) // loop and a half
  {
    auto next = iter+1; // at this point, we know iter != end
    while (next != end && next->empty())
      ++next;
    if (next == end)
      break;
    auto lhslast = lhs.end();
    --lhslast;
    if (lhslast->first > next->begin()->first)
      throw std::runtime_error("invalid key order");
    iter = next;
  }
}
编辑:

可以使用另一种算法进一步改进上述代码:

替换

while (iter != end && iter->empty())
  ++iter;

然后在代码所在的位置

auto fbegin = boost::make_filter_iterator(is_not_empty(), v.begin(), v.end());
auto fend =  boost::make_filter_iterator(is_not_empty(), v.end(), v.end());

if (std::adjacent_find(fbegin, fend,
                       [](std::map<double, double> const& lhs,
                          std::map<double, double> const& rhs) -> bool
                       {
                         auto lhslast = lhs.end();
                         --lhslast;
                         return lhslast->first > rhs.begin()->first;
                       }) != fend)
  throw std::runtime_error("invalid key order");
auto fbegin=boost::生成过滤器迭代器(不是空的(),v.begin(),v.end());
auto-fend=boost::生成过滤器迭代器(不是空的(),v.end(),v.end());
如果(std::相邻查找(fbegin、fend、,
[](标准::地图常量和左侧,
标准::地图常数和rhs)->bool
{
auto lhslast=lhs.end();
--lhslast;
返回lhslat->first>rhs.begin()->first;
})!=挡泥板)
抛出std::runtime_错误(“无效的密钥顺序”);

过滤器迭代器确保只考虑非空映射。

我认为标准库中没有合适的预定义算法来实现这一点。特别是,如果要为其定义一个相对复杂且有状态的谓词,可以使用
std::nextended\u find
,但这实际上相当于误用
std::nextended\u find
作为
std::for each
的某种替代品,也就是说,这与
std::nexture\u find
的最初目的没有多大关系

但是,您应该使用迭代器,而不是裸指针。我还建议将检查代码放入一个单独的函数中,可能名为
check
。以下是我的建议:

#include <vector>
#include <map>
#include <iostream>

bool check(const std::vector<std::map<double,double>> &v)
{
  /* Fast-forward to the first non-empty entry. */
  auto it = begin(v);
  for( ; it != end(v) ; ++it)
    if (!it->empty())
      break;

  /* We might be done by now. */
  if (it == end(v))
    return true;

  /* Else, go through the remaining entries,
     skipping empty maps. */
  auto prev = it->end();
  advance(prev,-1);
  ++it;

  for ( ; it != end(v) ; ++it)
    {
      if (!it->empty())
        {
          if (it->begin()->first < prev->first)
            return false;
          prev = it->end();
          advance(prev,-1);
        }
    }

  return true;
}

int main()
{
  std::vector<std::map<double,double>> v;

  /* Two entries for the vector, invalid order. */    
  v.push_back({ {1.0,1.0} , {2.0,4.0} });
  v.push_back({ {3.0,9.0} , {1.0,16.0} });

  if (!check(v))
    throw std::runtime_error("Invalid order of the maps in the vector.");

  return 0;
}
#包括
#包括
#包括
布尔检查(常数标准::向量和v)
{
/*快进到第一个非空条目*/
自动it=开始(v);
for(;it!=end(v);+it)
如果(!it->empty())
打破
/*我们现在可能已经完成了*/
如果(它==结束(v))
返回true;
/*否则,检查其余条目,
跳过空映射*/
auto prev=it->end();
预付款(前-1);
++它;
for(;it!=end(v);+it)
{
如果(!it->empty())
{
如果(it->begin()->firstfirst)
返回false;
prev=it->end();
预付款(前-1);
}
}
返回true;
}
int main()
{
std::向量v;
/*向量有两个条目,顺序无效。*/
v、 推回({1.0,1.0},{2.0,4.0});
v、 推回({3.0,9.0},{1.0,16.0});
如果(!检查(v))
抛出std::runtime_错误(“向量中映射的顺序无效”);
返回0;
}
注意:如果将
check
函数定义为一个以一系列迭代器(而不是容器引用)作为参数的算法,那么它将更像C++(或者至少更像标准库中的算法)。重写函数以匹配此概念是很简单的

注2:使用迭代器而不是裸指针的优点是,您可以更好、更清晰地抽象出所需内容:引用映射中某个项目的内容,而
double*
指针可以指向所有类型的内容。但是,使用迭代器也有一个缺点:如果要修改算法,使其在遍历向量时改变映射,则迭代器可能会失效,而指针不会失效(除非删除它指向的元素)。(不过,如果更改向量,指针可能会无效。)


但只要检查过程仅用于检查,而不用于其他用途(我的代码将代码放入专用于此目的的单独函数中,并将向量作为常量引用,这表明了这一点),迭代器无效就不是问题。

最著名的注释给出了答案:使用
相邻的\u-find

首先是一点逻辑。如果有nkey[m],则存在一个索引i,n key[i+i]

你可以用荒谬推理来证明这一点:如果没有这样的i,那么对于n和m之间的所有i,我们都有顺序,因为顺序关系是可传递的,key[n]first>r.cbegin()->first; }) != v、 end()) 抛出std::runtime_错误(“无效的密钥顺序”); 当然,如果您可以先从向量中删除空贴图,那么这就是。(我们可以假设,空映射可能没有那么大的意义,但这肯定取决于整个情况)。

这使用了一个C++1y功能(
std::tr2::optional
),但应适用于任何容器以及容器元素的任何排序:

struct compare_key_order {
  template<typename LHS, typename RHS>
  bool operator()( LHS const& lhs, RHS const& rhs ) {
    return lhs.first < rhs.first;
  }
};

template<typename ContainerOfContainers, typename Ordering>
bool are_container_endpoints_ordered( ContainerOfMaps&& meta, Ordering&& order=compare_key_order()  )
{
  using std::begin; using std::end;

  // or boost::optional:
  std::tr2::optional< decltype( begin(begin(meta)) ) > last_valid;

  for( auto&& Map : std::forward<Meta>(meta) ) {
    auto b = begin(Map);
    auto e = end(Map);
    if (b==e)
      continue;
    if (last_valid)
      if (!order( **last_valid, *b ))
        return false;
    last_valid = e;
  }
  return true;
}

这将使相同的算法可以在成对向量的向量上运行,甚至可以检查向量的向量是否具有排序端点(使用不同的
顺序)。

如何改为使用引用?还是我误解了这个问题?@H2CO3我考虑过引用,但是你能给引用赋值吗?你应该使用迭代器本身。它们充当指针。使用
std::nexting\u find
。有算法是有原因的。迭代器呢?如果向量的第一个条目是空映射呢?@jogojapan:请注意,我添加了第二个解决方案
filter\u iterator
解决方案很有趣。我只希望它支持lambda函数,而不是空结构。有语法错误。你能编译并更正代码吗?(顺便说一句,这个想法很有趣。我已经对你的答案投了赞成票,所以我不能再投反对票了……)我对错误感到抱歉;现在应该修好了。除了一些小错误(打字错误和常量缺失),主要问题是
map
没有
front
back
;必须用迭代器模拟它们(我还对第一个版本应用了相应的修复)。另外,我还想
auto fbegin = boost::make_filter_iterator(is_not_empty(), v.begin(), v.end());
auto fend =  boost::make_filter_iterator(is_not_empty(), v.end(), v.end());

if (std::adjacent_find(fbegin, fend,
                       [](std::map<double, double> const& lhs,
                          std::map<double, double> const& rhs) -> bool
                       {
                         auto lhslast = lhs.end();
                         --lhslast;
                         return lhslast->first > rhs.begin()->first;
                       }) != fend)
  throw std::runtime_error("invalid key order");
#include <vector>
#include <map>
#include <iostream>

bool check(const std::vector<std::map<double,double>> &v)
{
  /* Fast-forward to the first non-empty entry. */
  auto it = begin(v);
  for( ; it != end(v) ; ++it)
    if (!it->empty())
      break;

  /* We might be done by now. */
  if (it == end(v))
    return true;

  /* Else, go through the remaining entries,
     skipping empty maps. */
  auto prev = it->end();
  advance(prev,-1);
  ++it;

  for ( ; it != end(v) ; ++it)
    {
      if (!it->empty())
        {
          if (it->begin()->first < prev->first)
            return false;
          prev = it->end();
          advance(prev,-1);
        }
    }

  return true;
}

int main()
{
  std::vector<std::map<double,double>> v;

  /* Two entries for the vector, invalid order. */    
  v.push_back({ {1.0,1.0} , {2.0,4.0} });
  v.push_back({ {3.0,9.0} , {1.0,16.0} });

  if (!check(v))
    throw std::runtime_error("Invalid order of the maps in the vector.");

  return 0;
}
typedef map<double, double> map_t;
vector<map_t> v;
remove_if(v.begin(), v.end(), [](map_t const& m){return m.empty();});
if(adjacent_find(v.begin(), v.end(), [](map_t const& l, map_t const& r)
    {
        return (--l.cend())->first > r.cbegin()->first;
    }) != v.end())
    throw std::runtime_error("invalid key order");
struct compare_key_order {
  template<typename LHS, typename RHS>
  bool operator()( LHS const& lhs, RHS const& rhs ) {
    return lhs.first < rhs.first;
  }
};

template<typename ContainerOfContainers, typename Ordering>
bool are_container_endpoints_ordered( ContainerOfMaps&& meta, Ordering&& order=compare_key_order()  )
{
  using std::begin; using std::end;

  // or boost::optional:
  std::tr2::optional< decltype( begin(begin(meta)) ) > last_valid;

  for( auto&& Map : std::forward<Meta>(meta) ) {
    auto b = begin(Map);
    auto e = end(Map);
    if (b==e)
      continue;
    if (last_valid)
      if (!order( **last_valid, *b ))
        return false;
    last_valid = e;
  }
  return true;
}
struct compare_key_order {
  template<typename LHS, typename RHS>
  bool operator()( LHS const& lhs, RHS const& rhs ) {
    return lhs.first < rhs.first;
  }
};

template<typename ContainerOfContainers, typename Ordering>
bool are_container_endpoints_ordered( ContainerOfMaps&& meta, Ordering&& order=compare_key_order()  )
{
  using std::begin; using std::end;

  auto it = begin(meta);
  while( it != end(meta) && (begin(*it) == end(*it)) {
    ++it;
  }
  if ( it == end(meta) )
    return true;
  auto last_valid_end = end(*it);
  for( ++it; it != end(meta); ++it ) {
    auto b = begin(*it);
    auto e = end(*it);
    if (b==e)
      continue;
    if (!order( *last_valid_end, *b ))
      return false;
    last_valid = e;
  }
  return true;
}