Conversión de envoltorios de búfer nativos a C ++ / CLI

I am trying to port a native C++ library to C++/CLI, so I can use it in C#. I am trying to figure out how to convert a few of the classes that basically lightly wrap a buffer for extracting fields. I've written a small sample to better describe what is going on in the API.

Entonces, tengo un Packet class that reads packets from a file:

#include <fstream>
#include <cassert>
#include "OptionalA.h"

class Packet
{
public:
    Packet(void)
    {
        buffer = new char[PACKET_SIZE];
    }
    ~Packet(void)
    {
        delete [] buffer;
    }

    void ReadNextPacket(std::ifstream& fileStream)
    {
        fileStream.read(buffer, PACKET_SIZE);
    }

    bool HasOptionalA()
    {
        return (buffer[0] & 0x1) == 1;
    }

    OptionalA GetOptionalA()
    {
        assert(HasOptionalA());
        return OptionalA(&buffer[1], &buffer[1] + OptionalA::OPTIONAL_A_SIZE);
    }

private:
    const static int PACKET_SIZE = 3;
    char* buffer;
};

La Packet I created has a very simple format:

[Packet: <Header Byte> [OptionalA: <Field1><Field2>]]

La OptionalA la clase se define de la siguiente manera:

#pragma once
#include <cassert>

class OptionalA
{
public:
    static const int OPTIONAL_A_SIZE = 2;

    OptionalA(const char* begin = 0, const char* end = 0) :
    begin(begin), end(end)
    {
        assert((end - begin) == OPTIONAL_A_SIZE);
    }

    char GetField1()
    {
        return begin[0];
    }

    char GetField2()
    {
        return begin[1];
    }

private:
    const char* begin;
    const char* end;
};

What is the correct way to wrap this type of class architecture such that I duplicate the minimum amount of memory in C++/CLI?

preguntado el 30 de enero de 12 a las 19:01

1 Respuestas

a simple way, but somewhat time consuming depending on the amount of classes you have to convert, is to create CLI wrappers that contain a native pointer to the type they wrap:

ref class FileStream
{
public:
  FileStream( String^ file ) :
    p( new std::ifstream() )
  {
    //open the stream here, if it fails throw a managed exception that makes sense
  }

    //bonus: CLI classes automatically implement IDisposable so 
    //this gets called at the end of scope with 'using( var x = new FileStream(){}'
  ~FileStream()
  {
    delete p;
  }

    //make sure to implement a finalizer to make the GC work with this class
  !FileStream()
  {
    this->~FileStream();
  }

  //not repeating all functions here, we just use this as a placeholder
  std::ifstream& Stream()
  {
    return *p;
  }

private: 
  std::ifstream* p;
}

ref class Packet
{
public:
  Packet() :
    p( new native::Packet() )
  {
  }

  //again destructor/finalizer pair

  void ReadNextPacket( FileStream^ fileStream )
  {                   
    if( fileStream == nullptr )
      throw gcnew System::ArgumentNullException( "fileStream" );
    p->ReadNextPacket( fileStream->Stream() );
  }                   

  bool HasOptionalA()
  {
    return p->HasOptionalA();
  }

  OptionalA^ GetOptionalA()
  {
    retrun gcnew OptionalA( p->GetOptionalA() );
  }

private:
  native::Packet* p;
};

ref class OptionalA
{
public:
  OptionalA( const native::OptionalA& optionalA ) :
    p( new native::OptionalA( optionalA ) )
  {
  }

  //again destructor/finalizer pair

  char GetField1()    
  {    
    return p=>GetField1();   
  }    

private:
  native::OptionalA* p;
}

To spice things up and make better code, consider using something como este instead of raw native pointers and get cleanup for free. Also maybe consider using std::string and passing iterators around instead of raw char pointers, it's C++ after all.

Respondido 13 Abr '17, 15:04

I was going to recommend my smart pointer, then I saw you already did. Great choice! But please note that your code fails to implement a finalizer, and your comment that the destructor gets called automatically by the GC is wrong, it will leak if not explicitly disposed. It's somewhat tricky to get right, so use the smart pointer ;) - Ben Voigt

Also, I assume you intended to make FileStream::Stream a property? The syntax is wrong. - Ben Voigt

@BenVoigt thanks for pointing out those issues, I wrote everything from scratch so was bound to make some mistakes :] fixed it. - stijn

Thanks! I hadn't thought about using the default copy constructor to take advantage of const pointers. That's a clever idea :) - mevatron

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.