Pergunta

Em C#, é possível declarar uma estrutura (ou classe) que tem um ponteiro do tipo de membro, como este:

unsafe struct Node
{
  public Node* NextNode;
}

É seguro (err..ignorar por um momento que irônico pouco unsafe bandeira..) para utilizar esta construção?Quero dizer para armazenamento a longo prazo, no heap.Pelo que eu entendi, o GC é livre para mover as coisas ao redor, e enquanto ele atualiza as referências a algo que foi movido, não é atualizar os ponteiros também?Eu estou supondo que não, que iria fazer este tipo de construção muito inseguro, certo?

Eu tenho certeza que há uma maneira superior alternativas para fazer isso, mas chamá-lo de curiosidade mórbida.

EDITAR:Parece haver alguma confusão.Eu sei que esta não é uma grande construção, eu puramente quero saber se isso é sempre um seguro de construção, ou seja:é o ponteiro garantida para manter a apontar para o que você originalmente apontado que?

Original C-código foi usado para percorrer uma árvore (profundidade) sem recursividade, onde a árvore é armazenada em uma matriz.A matriz é então percorrida por incrementar um ponteiro, a menos que uma certa condição seja satisfeita, então o ponteiro é definido para o NextNode, onde a travessia continua.Claro, o mesmo pode em C# ser feito por:

struct Node
{
  public int NextNode;
  ... // other fields
}

Onde o int é o índice na matriz do próximo nó.Mas por motivos de desempenho, que eu acabaria mexer com ponteiros e fixed matrizes para evitar limites de cheques de qualquer maneira, e o original do C-código parecia mais natural.

Foi útil?

Solução

É seguro para usar esta construção?Quero dizer para o armazenamento a longo prazo no heap.

Sim.Fazendo assim normalmente é tolo, doloroso e desnecessário, mas é possível.

Pelo que eu entendi, o GC é livre para mover as coisas ao redor, e enquanto ele atualiza as referências a algo que foi movido, não é atualizar os ponteiros também?

Não. Por isso, fazemos de você marcar como seguro.

Eu estou supondo que não, que iria fazer este tipo de construção muito inseguro, certo?

Corrigir.

Eu tenho certeza que há uma maneira superior alternativas para fazer isso, mas chamá-lo de curiosidade mórbida.

Certamente há.

é o ponteiro garantida para manter a apontar para o que você originalmente apontado que?

Não, a menos que você assegurar que acontece.Há duas maneiras de fazer isso.

De uma maneira:Diga o coletor de lixo para não mover a memória.Há duas maneiras de o fazer:

  • Correção de uma variável no lugar com o "fixo" instrução.

  • Uso de serviços de interoperabilidade para criar um identificador gc para as estruturas que você deseja manter vivo e em um só lugar.

Ao fazer qualquer uma dessas coisas vai com alta probabilidade naufrágio, o desempenho do coletor de lixo.

Dois:Não tome referências à memória, que o coletor de lixo pode, possivelmente, avançar.Há duas maneiras de o fazer:

  • Só tomar endereços de variáveis locais, parâmetros de valor, ou pilha de blocos alocados.É claro que, em fazendo isso, você, em seguida, são necessárias para assegurar que os ponteiros não sobrevivem mais do que relevantes quadro de pilha, caso contrário, você é referência de lixo.

  • Alocar um bloco de heap não gerenciado e, em seguida, usar ponteiros dentro desse bloco.Em essência, implementar o seu próprio gerenciador de memória.Você são necessárias para implementar corretamente personalizado novo gerenciador de memória.Ser cuidadoso.

Outras dicas

Por que não:

struct Node
{
    public Node NextNode;
}

ou pelo menos:

struct Node
{
    public IntPtr NextNode;
}

Você poderia usar o fixo declaração para impedir que o GC mova ponteiros.

Sim, o coletor de lixo pode mover os objetos e, não, não atualizará seus ponteiros. Você precisa corrigir os objetos que apontar. Mais informações podem ser encontradas sobre isso Explicação de gerenciamento de memória.

Você pode consertar objetos como este:

  unsafe {
     fixed (byte* pPtr = object) {
         // This will fix object in the memory
        }
     }
  }

As vantagens dos ponteiros geralmente são desempenho e interação com outro código inseguro. Não haverá cheques fora dos limites, etc., acelerando seu código. Mas, como se você estivesse programando no por exemplo, você deve ter muito cuidado com o que está fazendo.

Algumas verificações óbvias de integridade foram excluídas. O problema óbvio com isso é que você precisa alocar mais do que precisará, porque não pode realocar o buffer como a palavra -chave fixo implica.

public unsafe class NodeList
{
    fixed Node _Nodes[1024];
    Node* _Current;

    public NodeList(params String[] data)
    {
        for (int i = 0; i < data.Length; i++)
        {
            _Nodes[i].Data = data[i];
            _Nodes[i].Next = (i < data.Length ? &_Nodes[i + 1] : null);     
        }

        _Current = &_Nodes[0];
    }

    public Node* Current()
    {
        return _Current++;  
    }
}

public unsafe struct Node
{
    public String Data;
    public Node* Next;
}

Uma ideia perigosa, mas pode funcionar:

Quando sua variedade de estruturas exceder um determinado tamanho (85000 bytes), será alocado no Grande heap de objeto onde os blocos são digitalizados e coletados, mas não movidos ...

O artigo vinculado aponta o perigo de que uma versão mais recente do CLR possa mover coisas no loh ...

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top