Ir ao conteúdo
  • Cadastre-se

C++ Estrutura de Dados, Alocação Dinâmica de Memória em C++ e leitura de dados


ROR

Posts recomendados

Eu tenho um código com encapsulamento e composição com 3 classes em C++. No meu código eu tenho de ciar os objetos de forma estática mas quero criá-los de forma dinâmica. Eu tenho uma classe chamada trabalhador que tem 2 objetos de outras 2 classes (info e familia) como seus membros, de forma que trabalhador tem info e familia. Toda vez que eu quero criar um objeto trabalhador (que tem info e familia) eu tenho de fazê-lo de forma manual (estática) mas quero fazê-lo dinamicamente. Eu quero que o usuário escolha quantos trabalhadores ele quer criar dinamicamente. Eu acho que eu deveria usar estruturas de dados como uma lista e alocação dinâmica de memória mas eu não sei como fazê-lo. Meu código também cria um arquivo chamado "cadastro.dat" e eu quero ler esse arquivo mas também não sei como fazê-lo. Alguém poderia me ajudar? Estou mostrando o código que já fiz.

//MAIN
#include <iostream>
using std::cerr;
using std::cin;
using std::cout;
using std::endl;
using std::ios;

#include <fstream> 
using std::ofstream;

#include <cstdlib>
using std::exit;

#include "trabalhador.h"

int main()
{
    ofstream saidaArquivoCadastro( "cadastro.dat", ios::out );
    
    if ( !saidaArquivoCadastro ) // operador ! sobrecarregado
 {
 cerr << "Arquivo nao pode ser aberto" << endl;
 exit( 1 );
 }
 
    cout << "INFORME OS DADOS SOLICITADOS: \n\n";
    cout << "Nome do funcionario: ";
    info i1;
    cout << "\nCPF: ";
    info i2;
    cout << "\nNome da mae: ";
    familia f1;
    cout << "\nNome do pai: ";
    familia f2;
    trabalhador t(i1, i2, f1, f2);
    
    return 0;
}



//trabalhador.h
#ifndef TRABALHADOR_H
#define TRABALHADOR_H

#include "info.h"
#include "familia.h"

class trabalhador
{
    public:
        trabalhador (const info &, const info &, const familia &, const familia &);
        void print () const;
    private:
        const info funcionarioNome;
        const info funcionarioCPF;
        const familia mae;
        const familia pai;
};

#endif



//trabalhador.cpp
#include <iostream>
using std::cout;

#include "trabalhador.h"
#include "info.h"

trabalhador::trabalhador (const info &infoNome, const info &infoCPF,
const familia &famiMae, const familia &famiPai)
:funcionarioNome (infoNome),
funcionarioCPF (infoCPF),
mae (famiMae),
pai (famiPai)
{
    cout << "\nDados do funcionario: \n";
    print();
}

void trabalhador::print() const
{
    funcionarioNome.print();
    funcionarioCPF.print();
    mae.print();
    pai.print();
}



//info.h
#include <string>
using std::string;

#ifndef INFO_H
#define INFO_H

class info
{
    public:
        info (string = "");
        void setInfoDado (string);
        void setInfo ();
        void print () const;
    private:
        string infoDado;
};

#endif



//info.cpp
#include <iostream>
using std::cout;
using std::cin;

#include <string>
using std::string;
using std::getline;

#include "info.h"

info::info (string info)
{
    setInfoDado (info);
}

void info::setInfoDado (string info)
{
    infoDado = info;
    setInfo();
}

void info::setInfo ()
{   
    string nome;
    getline (cin, nome);
    infoDado = nome;
}

void info::print () const
{
    cout << infoDado << "\n";
}



//familia.h
#include <string>
using std::string;

#ifndef FAMILIA_H
#define FAMILIA_H

class familia
{
    public:
        familia (string = "");
        void setFamiDado (string);
        void setFami ();
        void print () const;
    private:
        string famiDado;
};

#endif



//familia.cpp
#include <iostream>
using std::cout;
using std::cin;

#include <string>
using std::string;
using std::getline;

#include "familia.h"

familia::familia (string info)
{
    setFamiDado (info);
}

void familia::setFamiDado (string info)
{
    famiDado = info;
    setFami();
}

void familia::setFami ()
{   
    string nome;
    getline (cin, nome);
    famiDado = nome;
}

void familia::print () const
{
    cout << famiDado << "\n";
}

 

Link para o comentário
Compartilhar em outros sites

Caso não seja um programa que venha requerer demasiada eficiência ou trabalhar sobre um numero extremamente grande de objetos, você pode simplesmente utilizar um vetor (std::vector) de objetos do tipo trabalhador, i.e.

 

std::vector<trabalhador> lista; 

 

Dai você poderia colocar o menu do programa, responsável por perguntar os dados do trabalhador (ou a leitura do arquivo), num laço com fim determinado pelo próprio usuário, e ao fim de cada passo, com um novo objeto t devidamente criado, colocá-lo na lista de trabalhadores,

 

lista.std::vector<trabalhador>::push_back(t);

 

Toda a alocação dinâmica, realocação e liberação de recursos fica a cargo de std::vector e você não precisa se preocupar com isso. Quando terminar o processo de ler todos os trabalhadores, você pode checar o total com lista.std::vector<trabalhador>::size(). Toda a maquinaria de std::vector está na biblioteca <vector>.

 

Caso ainda não saiba usar "containers" como std::vector, ou o exercício seja parte de algum curso no qual o tema "containers" ainda não foi explicado, e portanto não possa usá-los ainda, ou o programa seja sensível a eficiência, etc. avise e podemos reformular as sugestões com a manipulação explicita da memoria usando os operadores newdelete e ponteiros do tipo trabalhador.

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

12 horas atrás, ROR disse:

Eu tenho um código com encapsulamento e composição com 3 classes em C++. No meu código eu tenho de ciar os objetos de forma estática mas quero criá-los de forma dinâmica. Eu tenho uma classe chamada trabalhador que tem 2 objetos de outras 2 classes (info e familia) como seus membros, de forma que trabalhador tem info e familia. Toda vez que eu quero criar um objeto trabalhador (que tem info e familia) eu tenho de fazê-lo de forma manual (estática) mas quero fazê-lo dinamicamente. Eu quero que o usuário escolha quantos trabalhadores ele quer criar dinamicamente. Eu acho que eu deveria usar estruturas de dados como uma lista e alocação dinâmica de memória mas eu não sei como fazê-lo. Meu código também cria um arquivo chamado "cadastro.dat" e eu quero ler esse arquivo mas também não sei como fazê-lo. Alguém poderia me ajudar? Estou mostrando o código que já fiz

 

  • O modo de criar não faz diferença a menos que aloque memória em alguma das classes
  • as classes internas se só aparecem internamente podem ser declaradas dentro da classe container. Fica mais fácil de ler e manter
  • se quer flexibilidade na alocação use uma classe container tipo Trabalhadores e lá crie um vetor, algo como 
     
        vector<Trabalhador> T;

    e assim poderá usar os mecanismos de alocaçào que já existem para o vetor e não se preocupar com endereços e memória
  • Para ler e gravar o arquivo pode usar mesmo read/write, mas em termos de estruturas.
  • Curtir 1
Link para o comentário
Compartilhar em outros sites

@V!OLADOR eu faço isso na main mesmo (no momento de criar o objeto)? Eu posso fazer um for que seja do tamanho da quantidade de trabalhadores que o usuário vai criar, algo como:

 

int numero;

cout << "informe a quantidade de trabalhadores: ";

cin >> numero;

for (i = 0; i < numero; i++)

 

mas qual a sintaxe eu uso pra passar numero para o vetor (vamos supor que o usuário queira criar 10 objetos trabalhador. como o compilador diferencia cada um 10 objetos, como é feita a indexação)? e qual a sintaxe eu uso para que um objeto específico do vetor chame um método (como eu faço a indexação para que um objeto específico chame um método)?

 

tem como dar um exemplo prática de como ficaria em um código?

Link para o comentário
Compartilhar em outros sites

4 horas atrás, ROR disse:

mas qual a sintaxe eu uso pra passar numero para o vetor (vamos supor que o usuário queira criar 10 objetos trabalhador. como o compilador diferencia cada um 10 objetos, como é feita a indexação)? e qual a sintaxe eu uso para que um objeto específico do vetor chame um método (como eu faço a indexação para que um objeto específico chame um método)?

Eu já te expliquei isso, e a maior parte do que está errado em seu programa :( 

 

4 horas atrás, ROR disse:

tem como dar um exemplo prática de como ficaria em um código?

 

e te mostrei também um exemplo...

 

    trabalhador* WorkForce = new trabalhador[20];
    WorkForce[19].print();
    delete[] WorkForce;

 

sobre esse mesmo programa, num tópico que você abriu aqui...

image.png.34850520852fec078df51592a70799d9.png

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

7 horas atrás, ROR disse:

@V!OLADOR eu faço isso na main mesmo (no momento de criar o objeto)? Eu posso fazer um for que seja do tamanho da quantidade de trabalhadores que o usuário vai criar, algo como:

 

int numero;

cout << "informe a quantidade de trabalhadores: ";

cin >> numero;

for (i = 0; i < numero; i++)

 

mas qual a sintaxe eu uso pra passar numero para o vetor (vamos supor que o usuário queira criar 10 objetos trabalhador. como o compilador diferencia cada um 10 objetos, como é feita a indexação)? e qual a sintaxe eu uso para que um objeto específico do vetor chame um método (como eu faço a indexação para que um objeto específico chame um método)?

 

tem como dar um exemplo prática de como ficaria em um código?

 

Bom, como fazer depende dos objetivos do programa, daquilo que você tem em mente pra ele. Se eu fosse modificar seu programa em cinco minutos eu faria algo como,

 

std::vector<trabalhador> lista;

// ...

while (true)
{
	std::cout << "INFORME OS DADOS SOLICITADOS: \n\n";
	std::cout << "Nome do funcionario: ";
	info i1;
	std::cout << "\nCPF: ";
	info i2;
	std::cout << "\nNome da mae: ";
	familia f1;
	std::cout << "\nNome do pai: ";
	familia f2;
	trabalhador t(i1, i2, f1, f2);
  
	lista.std::vector<trabalhador>::push_back(t);
  
//	TODO: perguntar ao usuario se ele gostaria de terminar o cadastro de trabalhadores e terminar o loop caso positivo
}

 

no main mesmo, caso não haja razão pra fazer um rotina separada. E depois você poderia acessar o n-ésimo trabalhador da sua lista facilmente usando um iterador:

 

for (std::vector<trabalhador>::iterator n = lista.std::vector<trabalhador>::begin(); n != lista.std::vector<trabalhador>::end(); ++n)
{  
	n->print(); // acessando o membro print() da classe trabalhador no n-esimo elemento da lista
}

 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

eu fiz um exemplo mais simples usando o operador new. seria algo nesse estilo? eu testei inserindo 5 usuários e funcionou em um compilador online mas quando eu tento inserir 10 elementos ele roda mas apresenta uma msg de erro no final.

 

@V!OLADOR @arfneto

//main
#include <iostream>
using std::cout;
using std::cin;

#include "memoria.h"

int main ()
{
	int numero;
	int i;
	cout << "informe a quantidade de usuarios: ";
	cin >> numero;
	
		
	for (i = 0; i < numero; i++)
	{
	memoria* m = new memoria[i];
	m[i].setValor();
	m[i].imprime();
	delete[] m;
	}
	
				
	return 0;
}
                           
//memoria.h
class memoria
{
	public:
		void setValor();
		void imprime();
	private:
		int valor;
};
                           
//memoria.cpp
#include <iostream>
using std::cout;

#include "memoria.h"

void memoria::setValor()
{
    valor = 20;
}

void memoria::imprime()
{
	cout << valor << "\n";
}

 

Link para o comentário
Compartilhar em outros sites

Ótimo, parabéns. Em C++ é sempre preferível usar o std::vector porque ele cuida de toda a parte burocrática sobre alocar recursos, liberar recursos além de varias funcionalidades pré-prontas. Assim, você precisa apenas se preocupar com o problema que gostaria resolver. Então, caso utilizado corretamente, eles podem ser tão eficientes quanto um array do C e mais versáteis, ou seja, devemos usá-los sempre que possível.

 

Mas há um detalhe: eles permitem que sejam utilizados de forma incorreta (não ótima). Então, caso a aplicação demande eficiência, um std::vector mal utilizado pode degradar a eficiência do programa. Basicamente uma questão de (re)educação das boas práticas pra usá-los eficientemente. Os arrays (ou ponteiros) tradicionais não possuem esse caviat de serem bem ou mal utilizados, eficiência é quase garantida pela natureza da simplicidade, mas são perigosos por outras razões. 

 

O exemplo que dei pra você usando a função push_back( ), por exemplo, seria ideal pra um caso de algumas centenas de trabalhadores mas extremamente ruim caso seu objetivo fosse cadastrar os tralhadores da Índia (1.3 bilhões de entradas). Isso porque o vetor poderia eventualmente realocar 1.3 bilhões elementos na memoria; além disso o construtor da sua classe trabalhador seria invocado 1.3 bilhões de vezes pra criar o objeto t do seu código original; teríamos 1.3 bilhões de chamadas da própria função push_back( ) etc. Então deveríamos redesenhar todo o algorítimo pra evitar tudo isso.  Por exemplo, usando a função reserve( ) pra pré-alocar memoria.

 

Com arrays (ou ponteiros) tradicionais quase nada desse trabalho extra seria necessário mas deveríamos tomar conta da alocação, dos tamanhos, etc. pessoalmente.

 

Na duvida, sempre use std::vector.

Link para o comentário
Compartilhar em outros sites

6 minutos atrás, ROR disse:

Tradicionalmente o C++ não trabalha com recursos como malloc, realloc, calloc, etc, correto? São recursos de C, no mínimo, evitados em C++, não é isso?

 

As funções equivalentes em C++ são new e delete, ou as versões new [] e delete [] para arrays. No entanto desde 2011 não há qualquer incentivo para alocação de memória ou liberação usando essas primitivas. 

 

Então na verdade se pode dizer que recursos "evitados" em C++ são os sucessores de malloc() e família do C. Ao menos é o que se vê nas recomendações, livros e políticas de uso como os core guidelines 

 

A recomendação desde 2011 é usar unique_ptr<> e shared_ptr<> para alocar memória a menos que se tenha uma forte razão para não usar. E se tiver uma razão realmente forte para usar new e delete usar RAII e alocar nos construtores e liberar nos destrutores. A razão é simples: usando unique_ptr<> e shared_ptr<> a liberação é automática --- não existe free() ou delete --- e o controle de uso é muito mais preciso.

 

E quando possível é melhor usar os containers disponíveis na biblioteca padrão, filas, dicionários. listas, conjuntos... A chance de uma empresa qualquer ter um grupo de desenvolvedores do nível dos caras que escreveram a STL é mínima... 

 

 

 

Link para o comentário
Compartilhar em outros sites

@arfneto Complicado!! hahaha. Vocês têm alguma recomendação de livro mais técnico que trata essas abordagens e "boas práticas"? Eu to usando o livro do Deitel de 2006 para ter uma base, uma "noção" sobre classes, objetos, relacionamento, encapsulamento, polimorfismo, etc, mas to vendo que terei de usar livros mais novos pra usar os recursos mais atualizados. E eu queria ver um livro com uns exemplos maiores, mais complexos. Os livros do Deitel tem exemplos mais "simples", entre 80 a 150 linhas... Queria uns exemplos de programas completos, mais robustos, que usasse várias dessas técnicas e conceitos em um único programa. Qual compilador vcs costumam usar? E entre C++, Java, Python e C#, qual vcs acham mais robusto e que mais está sendo utilizado nas aplicações atuais?

Link para o comentário
Compartilhar em outros sites

52 minutos atrás, ROR disse:

Complicado!! hahaha

 

Na verdade é mais simples agora do que antes.

 

53 minutos atrás, ROR disse:

Queria uns exemplos de programas completos, mais robustos, que usasse várias dessas técnicas e conceitos em um único programa

 

Não conheço algo assim. E eu procuraria justamente o contrário: os programas pequenos com exemplos mais específicos. E assim não vou saber recomendar algum que fosse diferente. Também nunca li nada desse Deitel de que falou então também não sei julgar. 

 

Talvez alguém aqui tenha mais noção. 

 

O melhor livro que já li sobre isso foi "A Tour of C++" de Bjarne Stroustrup.

 

Sobre as "boas práticas" a bíblia é o link que mostrei no outro post: C++ Core Guidelines. E lá tem referências sobre muitos autores importantes. como Herb Sutter, Scott Meyers e claro o prof. Stroustrup.

 

Em 10 de outubro, 2020 o próprio Herb Sutter, um dos maiores arquitetos da linguagem, deixou uma referência sobre isso em uma conferência que pode ser vista no Youtube em https://www.youtube.com/watch?v=6lurOCdaj0Y&t=870s

 

 

Sobre as linguagens, esse é um forum sobre C, C++ e C#. Um lugar para discussões políticas e apaixonadas sobre qual linguagem é melhor seria algum site como Discord ou Quora, imagino. Como não quero provar nada não frequento e então não sei quase nada sobre eles. Mas são grátis até onde eu sei.

 

Sobre essas 3 se me perguntar vou dizer que são diferentes animais. Programas em C tendem a ser compactos e rápidos. C é uma linguagem elegante e poderosa. Tudo praticamente foi escrito em C, no todo ou em grande parte. C++ é sensacional para modelar coisas complicadas que podem levar uma era em C. E para programar jogos é quase unanimidade. E é uma linguagem sensacional, mas gigante e eu diria que é difícil. C# associada a .Net é algo poderoso para negócios por exemplo. E Unity, o framework para jogos, roda em torno de C# e C++. C# é muito similar a java, assim como um parte de C++. Mas em geral não se escolhe essas coisas: quem define é quem está pagando. Ou mesmo a escola. Off-topic mas posso dizer que Python é fácil. Muito fácil, Foi escrita com isso em mente. E tem um grande número de bibliotecas, disponíveis para tudo. Quase tudo escrito em... C.  E é grátis. E lerdo.

 

 

 

Link para o comentário
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...