Retornar estrutura ou classe [RESOLVIDO]

1. Retornar estrutura ou classe [RESOLVIDO]

Samuel Leonardo
SamL

(usa XUbuntu)

Enviado em 27/07/2016 - 00:15h

Andei vendo o source da lib SDL2 e notei algo interessante: eles não retornam estruturas, ao invés disso os devs usam um argumento a mais na função, um ponteiro no caso para uma struct do tipo requerido, assim internamente no corpo da função o ponteiro é usado para preencher a struct.
Não achei ainda uma função no SDL que retornasse uma struct que não seja ponteiro.
Então, é tão lento assim retornar um tipo de dado, digamos assim, mais "pesado"?


  


2. Re: Retornar estrutura ou classe [RESOLVIDO]

Uilian Ries
uilianries

(usa Linux Mint)

Enviado em 27/07/2016 - 09:03h

Quando um uma função retorna por struct, a estrutura é retornada por cópia (Obs: isso não é uma obrigação, elisão de cópia é uma implementação do compilador).


struct foo {
int quz;
char couse;
};

struct foo bar(int quz, char couse)
{
struct foo f = { quz, couse };
return f;
}

struct foo foobar = bar(42, 'P');


Esse código compila, executa e todos vão felizes pra casa, menos os frenéticos por otimização. Observe que struct foo f é local, e ao final da função bar, será destruída. Então é realizado uma cópia de f para foobar.


struct foo {
int quz;
const char* couse;
};

struct foo make_foo()
{
char message [] = {"VIVAOLINUX"};
struct foo f = { 42, &message[0] };
return f;
}

struct foo foobar = make_foo();


Esse código compila, mas silenciosamente, o compilador não avisa sobre a armadilha na função make_foo. O problema aqui é message ser desalocado ao final da função e a variável foobar não possuir a cópia da string "VIVAOLINUX".


struct foo {
int quz;
char couse;
};

void make_foo(struct foo* somefoo)
{
somefoo->quz = 42;
somefoo->couse = 'P';
}

struct foo foobar;
make_foo(&foobar);


Neste exemplo, não existe a cópia temporária, pois a função make_foo não usa uma estrutura local.

--
Uilian Ries


3. Re: Retornar estrutura ou classe

Paulo
paulo1205

(usa Ubuntu)

Enviado em 27/07/2016 - 15:10h

Um dos motivos de usar ponteiro é para minimizar a quantidade de dados a serem passados de um lado para outro. Não resta dúvidas de que se você tiver uma estrutura cujo tamanho é maior do que o tamanho de um ponteiro, será mais simples copiar apenas o endereço do objeto do que seu conteúdo. Mas nem sempre é o caso. Numa máquina de 64 bits, um dado do tipo struct in_addr acaba sendo menor do que o ponteiro para essa estrutura.

Mas às vezes a razão não é apenas eficiência. Com frequência você não quer que o usuário tenha acesso aos campos internos de uma estrutura, para não interferir diretamente sobre dados que você quer deixar exclusivamente a cargo da sua biblioteca. O que você pode fazer nesse caso é entregar ao usuário um cabeçalho que contém apenas uma forward declaration da sua estrutura, possivelmente associada a um nome mais simples por meio de algum typedef, mas a declaração completa da estrutura nunca aparece por meio do cabeçalho, pois todas as funções que manipulam dados daquele tipo o fazem através de ponteiros.

O próprio compilador não precisa da declaração completa para tratar ponteiros daquele tipo: todos os ponteiros têm o mesmo tamanho, então ele sabe quantos bytes alocar para argumentos ponteiros passados à função e quantos bytes receber quando um ponteiro é retornado pela função. Além disso, o nome do tipo, mesmo sendo um tipo que não esteja completamente definido, é suficiente para ele saber distinguir ponteiros para dados daquele tipo de ponteiros para dados de outros tipos, e assim alertar se você tentar atribuir endereços entre ponteiros para dados incompatíveis entre si.

Você certamente já usou muito isso, mesmo antes de observar a SDL. O tipo FILE de <stdio.h> é um tipo incompleto, de modo que você sempre trabalha com ponteiros para esse tipo, desde o momento da construção do objeto, por meio da função fopen(), ao longo de sua vida, em que ele pode ser objeto de manipulações por meio de funções de I/O, até o momento em que ele for desconstruído, através de fclose(). (A título de curiosidade, imagine se cada pessoa que vem a este fórum perguntando sobre como limpar o buffer de entrada tivesse acesso aos campos internos de um objeto do tipo FILE.)






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner
Linux banner
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts