Re: [ccppbrasil] Re: impedindo passar como parâmetro - explicando melhor

19 views
Skip to first unread message

Canellas

unread,
May 14, 2013, 8:02:05 AM5/14/13
to ccppbrasil
Obrigado pelas respostas!

O que gostaria é que um objeto não pudesse ser usado em uma thread diferente da que foi declarado/instanciado. Então na verdade ele pode ser passado como parâmetro para funções dentro da mesma thread.

Como já escrevi como deleted o copy e move constructor, só consegui passar um objeto para uma nova thread via 'std::ref'.

Exemplo:

01 class A {
02 public:
03     A() {...}
04     A(const A &) = deleted;
05     A(const A &&) = deleted;
06  };

07 void g( A & a ) {...}

08 void f() {
09     A a;
10     g(a); // ok, dentro da mesma thread
11     std::thread t1( g, a ); // erro de compilação, como desejado
12     std::thread t2( g, std::move( a ) ); // erro de compilação, como desejado
13     std::thread t3( g, std::ref( a ) ); // compila, como *não* desejado
14 }


Portanto, que queria evitar que a linha 13 sequer compilasse. Possível?

Grato,


  


    Rodrigo Canellas

    -----------
    Programador C++
    Fotógrafo amador
 




Em 14 de maio de 2013 01:36, Уθя¡ςκ <obl...@gmail.com> escreveu:
On Monday, May 13, 2013 10:47:15 PM UTC-3, Rodrigo.Canellas wrote:
Olá,

O assunto poderia ser: 'como garantir que objetos só existam localmente em uma fç?'

Para isso, eu queria impedir que objetos de uma classe fossem passados como parâmetros, seja por valor (esse eu consegui), por & ou por std::move, garantindo (eu acho) q só existam locais em uma fç.

Exemplificando:

class A {
public:
    A() {}
    A(const A &) = delete;
    A(A &&) = delete;

    A & operator =(const A & ) = delete;
    A & operator =( A && ) = delete;
};

void f( A & a ) {...}
void g( A && a ) {...}
void h( A a ){...}

.
.
.
A a;
f(a);
g(std::move(a));
h(a);


'h' não vai compilar, mas 'f' e 'g' compilam (e funcionam). Eu queria que 'f' e 'g' nem compilassem.

Eu tentei achar como  sobrescever o 'operador &' como deleted, mas não deu em nada.

'Tô viajando ou existe como fazer isso? 

Tente ver o que você está querendo fazer fora do contexto de passagem de parâmetros que talvez fique mais explicito e clara a impossibilidade. Um parâmetro referência é uma referência, então, você conseguiria impedir que sejam criadas simples referências para objetos de suas classes? Você consegue impedir que o programador crie um ponteiro que aponte para objetos da sua classe? Isso, é independente do construtores de cópia, que servem na criação de objetos da sua classe, mas não dizem nada a respeito dos derivados (referencias, ponteiros, arrays, ...).

--
Antes de enviar um e-mail para o grupo leia:
http://www.ccppbrasil.org/wiki/Lista:AntesdePerguntar
--~--~---------~--~----~---------------------------------~----------~--~----~
[&] C & C++ Brasil - http://www.ccppbrasil.org/
Para sair dessa lista, envie um e-mail para ccppbrasil-...@googlegroups.com
Para mais opções, visite http://groups.google.com/group/ccppbrasil
--~--~---------~--~----~--~-~--~---~----~-----------------~--~----------~
Emprego & carreira: vag...@ccppbrasil.org
http://groups.google.com/group/dev-guys?hl=en
 
 
 

Gianni

unread,
May 14, 2013, 8:15:41 AM5/14/13
to ccppb...@googlegroups.com
Se seu objetivo é só fazer isso, acho que o mais fácil e, muito mais
importante, mais *claro* é fazer o construtor desse classe pegar o
std::this_thread::get_id(), e em todos as funções membro colocar um:
assert(std::this_thread::get_id(), _original_thread_id).

Incluindo ainda uma macro para retirar esse código da versão release, e ainda
com uma mensagem bem clara no std::cerr antes do assert, fica muito mais fácil
escrever, e muito mais fácil debugar no futuro.
> Programador C++ <http://code.google.com/p/tenacitas/>
> Fotógrafo amador <http://photo.net/photos/RodrigoCanellas>
> > --~ [&] C & C++ Brasil - http://www.ccppbrasil.org/

Canellas

unread,
May 14, 2013, 8:19:07 AM5/14/13
to ccppbrasil
Obrigado pela resposta!

Foi mais ou menos isso que fiz... mas gostaria mesmo de pegar em compilação...

    Rodrigo Canellas

    -----------
    Programador C++

P.

unread,
May 14, 2013, 10:45:30 AM5/14/13
to ccppb...@googlegroups.com

Em terça-feira, 14 de maio de 2013 09h02min05s UTC-3, Rodrigo.Canellas escreveu:
 
Obrigado pelas respostas!

O que gostaria é que um objeto não pudesse ser usado em uma thread diferente da que foi declarado/instanciado. Então na verdade ele pode ser passado como parâmetro para funções dentro da mesma thread.

Como já escrevi como deleted o copy e move constructor, só consegui passar um objeto para uma nova thread via 'std::ref'.


Com certeza std::ref não é a única alternativa para acessar um objeto a partir de uma outra thread, mesmo assumindo que esta thread foi iniciada como efeito do construtor de std::thread.

O seguinte compila no Visual Studio 2012.

#include <thread>

struct A
{
    A () { }
private:
    A (A const &);
    A (A const &&);
public:
    void foo () { }
};

struct Lambda
{
  A & a;
  Lambda (A & a_) : a(a_) { }
  void operator() () { a.foo(); }
};

void foo0 ()
{
  A a;
  Lambda lambda (a);
  std::thread t (lambda);
}

void foo1 ()
{
   A a;
   auto lambda = [&] () { a.foo(); };
   std::thread t (lambda);
}


--
 P.

Felipe Magno de Almeida

unread,
May 14, 2013, 10:48:39 AM5/14/13
to ccppb...@googlegroups.com
2013/5/14 Canellas <rodrigo....@gmail.com>

Obrigado pela resposta!

Foi mais ou menos isso que fiz... mas gostaria mesmo de pegar em compilação...

A única forma de pegar esse tipo de coisa em tempo de compilação é com um sistema de tipos substrutural. Que não é o caso do C++.
 
    Rodrigo Canellas

    -----------
    Programador C++
    Fotógrafo amador
 
--
Felipe Magno de Almeida

Thiago Adams

unread,
May 14, 2013, 12:22:25 PM5/14/13
to ccppb...@googlegroups.com
Qual a motivação?


Canellas

unread,
May 14, 2013, 12:34:40 PM5/14/13
to ccppbrasil
A motivação não é o mais importante, agora, mas sim tentar aprender como implementar certos requisitos, por mais "esquisitos" q possam parecer.

Mas, para contextualizar, o objetivo é Log. Gostaria q o objeto q loga msgs da thread A não pudesse, em compilação, ser passado para uma thread B, pois registraria msgs de B na mídia destinada às msgs de A (supondo mídias separadas por thread, p/ diminuir concorrência na gravação - ao menos foi isso q eu pensei).

    Rodrigo Canellas

    -----------
    Programador C++
    Fotógrafo amador
 




2013/5/14 Thiago Adams <thiago...@gmail.com>
Qual a motivação?


Gianni .

unread,
May 14, 2013, 12:42:23 PM5/14/13
to ccppb...@googlegroups.com

E se vc não tentar impedir? Ao invés disso, criar um std::map<thread_id, Log>? :-)

 

Acho que o que vc quer implementar exatamente é impossível....

Canellas

unread,
May 14, 2013, 12:42:07 PM5/14/13
to ccppbrasil
Sim, já me convenci q é impossível (quem sou eu p discordar do Felipe Magno de Almeida!!).

E,sim, eu já tenho um map parecido c/ esse. A saída foi checar em tempo de execução se o objeto log está logando na thread na qual foi criado.

    Rodrigo Canellas

    -----------
    Programador C++
    Fotógrafo amador
 




2013/5/14 Gianni . <nasus....@gmail.com>

Gianni .

unread,
May 14, 2013, 12:53:51 PM5/14/13
to ccppb...@googlegroups.com

Então, a minha dica é não expor esse objeto totalmente.

 

Você pode fazer que ele só possa ser acessado por membros de classe estáticos. E esses membros repassam a chamada à um objeto que está dentro do mapa.

 

Por exemplo:

 

class Log

{

private:

static std::map<std::thread::id, Log> _logs;

 

Log();

 

void _logMessage(std::string);

 

public:

static void logMessage(std::string str)

{

_logs[std::this_thread::get_id()]._logMessage(str);

}

}

 

 

Assim, fica seguro e não precisa checar necessariamente.

Rodrigo Madera

unread,
May 14, 2013, 12:51:22 PM5/14/13
to ccppb...@googlegroups.com
Eu nem usaria objetos. Uma free function resolve perfeitamente.

Mx


2013/5/14 Gianni . <nasus....@gmail.com>

--

Thiago Adams

unread,
May 14, 2013, 12:51:58 PM5/14/13
to ccppbrasil


On May 14, 1:34 pm, Canellas <rodrigo.canel...@gmail.com> wrote:
> A motivação não é o mais importante, agora, mas sim tentar aprender como
> implementar certos requisitos, por mais "esquisitos" q possam parecer.
>
> Mas, para contextualizar, o objetivo é Log. Gostaria q o objeto q loga msgs
> da thread A não pudesse, em compilação, ser passado para uma thread B, pois
> registraria msgs de B na mídia destinada às msgs de A (supondo mídias
> separadas por thread, p/ diminuir concorrência na gravação - ao menos foi
> isso q eu pensei).

Não sei que compiladores já implementam, mas o "thread_local"do C++ 11
permite que seja criada/usada uma variável para cada thread
específica.

thread_local Log threadlog;



Gianni .

unread,
May 14, 2013, 12:57:20 PM5/14/13
to ccppb...@googlegroups.com
sim, mas ela ainda pode ser passada para outra thread, por endereço ou
referência...etc..

Canellas

unread,
May 14, 2013, 12:53:29 PM5/14/13
to ccppbrasil
Mas um objeto 'thread_local' não pode ser passado para outra thread?

    Rodrigo Canellas

    -----------
    Programador C++
    Fotógrafo amador
 




Vinícius dos Santos Oliveira

unread,
May 14, 2013, 12:57:30 PM5/14/13
to ccppbrasil
Em 14 de maio de 2013 13:57, Gianni . <nasus....@gmail.com> escreveu:
> Não sei que compiladores já implementam, mas o "thread_local"do C++ 11
> permite que seja criada/usada uma variável para cada thread
> específica.
>
> thread_local Log threadlog;

sim, mas ela ainda pode ser passada para outra thread, por endereço ou
referência...etc..

Mesmo assim, ainda serve como uma segunda escolha de implementação para a "free function" que foi citada anteriormente, com a vantagem de dispensar lock guards para o map.


--
Vinícius dos Santos Oliveira

Gianni .

unread,
May 14, 2013, 1:04:22 PM5/14/13
to ccppb...@googlegroups.com

No exemplo simplório que eu mandei sim, thread local é até melhor (se não tem o padrão, todo compilador tem seu próprio)

 

Mas se o contrutor da classe Log for mais complexo, ou algo do tipo, aí não dá p/ usar...

Felipe Magno de Almeida

unread,
May 14, 2013, 1:13:32 PM5/14/13
to ccppb...@googlegroups.com
2013/5/14 Canellas <rodrigo....@gmail.com>

Mas um objeto 'thread_local' não pode ser passado para outra thread?

 Não se você não expor objetos. Apenas funções-livres e usar TSS como implementation-detail.
 
    Rodrigo Canellas

    -----------
    Programador C++
    Fotógrafo amador 

P.

unread,
May 14, 2013, 2:23:12 PM5/14/13
to ccppb...@googlegroups.com
Em terça-feira, 14 de maio de 2013 13h34min40s UTC-3, Rodrigo.Canellas escreveu:
 
A motivação não é o mais importante, agora, mas sim tentar aprender como implementar certos requisitos, por mais "esquisitos" q possam parecer.

Mas, para contextualizar, o objetivo é Log. Gostaria q o objeto q loga msgs da thread A não pudesse, em compilação, ser passado para uma thread B, pois registraria msgs de B na mídia destinada às msgs de A (supondo mídias separadas por thread, p/ diminuir concorrência na gravação - ao menos foi isso q eu pensei).


C++ não permitirá constranger a formação de referências com o rigor desejado.

Onde um nome X qualquer estiver acessível, em geral é possível formar uma referência para X.

A realização desse fato tende a levar ao pânico os indivíduos excessivamente interessados em "private" quando estes percebem que é perfeitamente possível passar uma referência a um nome qualquer para fora do contexto "private":

/***
 * OH MEU DEUS NÃO EXISTE ENCAPSULAMENTO EM C++
 **/

class A
{
   int super_secret;

public:

   int & reveal_super_secret ();

}


Suponho que a solução real para o seu problema, em C++11, está ao redor da palavra-chave thread_local.

--
 P.
Reply all
Reply to author
Forward
0 new messages