0

I am trying to port this function from Linux to windows:

template<class TDescriptor, class F>
bool TemplatedVocabulary<TDescriptor,F>::loadFromBinaryFile(const std::string &filename) {
  fstream f;
  f.open(filename.c_str(), ios_base::in|ios::binary);
  unsigned int nb_nodes, size_node;
  f.read((char*)&nb_nodes, sizeof(nb_nodes));
  f.read((char*)&size_node, sizeof(size_node));
  f.read((char*)&m_k, sizeof(m_k));
  f.read((char*)&m_L, sizeof(m_L));
  f.read((char*)&m_scoring, sizeof(m_scoring));
  f.read((char*)&m_weighting, sizeof(m_weighting));
  createScoringObject();

  m_words.clear();
  m_words.reserve(pow((double)m_k, (double)m_L + 1));
  m_nodes.clear();
  m_nodes.resize(nb_nodes+1);
  m_nodes[0].id = 0;
  char buf[size_node];// fails

  int nid = 1;
  while (!f.eof()) {
    f.read(buf, size_node);
    m_nodes[nid].id = nid;
    // FIXME
    const int* ptr=(int*)buf;
    m_nodes[nid].parent = *ptr;
    //m_nodes[nid].parent = *(const int*)buf;
    m_nodes[m_nodes[nid].parent].children.push_back(nid);
    m_nodes[nid].descriptor = cv::Mat(1, F::L, CV_8U);
    memcpy(m_nodes[nid].descriptor.data, buf+4, F::L);
    m_nodes[nid].weight = *(float*)(buf+4+F::L);
    if (buf[8+F::L]) { // is leaf
      int wid = m_words.size();
      m_words.resize(wid+1);
      m_nodes[nid].word_id = wid;
      m_words[wid] = &m_nodes[nid];
    }
    else
      m_nodes[nid].children.reserve(m_k);
    nid+=1;
  }
  f.close();
  return true;
}

This line:

char buf[size_node];

will not compile, giving the error:

expression did not evaluate to a constant.

I have tried using:

std::vector<char> buf(size_node)

and:

char buf[size_node] = new char[];

but I see the same error. It seems like this is related to a run time constant vs compile time constant, as stated in the answer here:

Tuple std::get() Not Working for Variable-Defined Constant

But I am not sure how to get around it in this case. Thank you.

anti
  • 2,565
  • 3
  • 26
  • 62
  • 6
    GCC supports variable length arrays as an extension (which is what you have), while standard C++ doesn't. This is why you should always build with `-pedantic`. I don't know how you tried `vector`, but it should work. – StoryTeller - Unslander Monica Jun 15 '17 at 09:05
  • 4
    C++ doesn't have [variable-length arrays](https://en.wikipedia.org/wiki/Variable-length_array). Some compilers add it as an *extension* of the language. Use [`std::vector`](http://en.cppreference.com/w/cpp/container/vector) instead. – Some programmer dude Jun 15 '17 at 09:05
  • 4
    A couple of other things: Array indexes are *zero based*. An array (or a vector) of `size_node` elements have indexes from `0` to `size_node - 1` (inclusive). Then read [Why is iostream::eof inside a loop condition considered wrong?](https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong) – Some programmer dude Jun 15 '17 at 09:07
  • Also see [How do compilers treat variable length arrays](https://stackoverflow.com/q/7627235/608639) and [How does GCC implement variable-length arrays?](https://stackoverflow.com/q/21182307/608639) – jww Jun 15 '17 at 17:24

1 Answers1

4

It should be

char *buf = new char[size_node];

Remember to delete the memory after use.

Or, just use std::vector. It's much safer.

std::vector<char> buf(size_node);

Then you'd have to change how buf is used. For example:

f.read(buf, size_node);

should become

f.read(buf.data(), size_node); //Only C++11
nakiya
  • 12,981
  • 20
  • 67
  • 111