Si declaro un objeto envuelto en un puntero:

std::shared_ptr<myClass> myClassObject(new myClass());

entonces yo quería pasar como argumento a un método:

DoSomething(myClassObject);

//the called method
void DoSomething(std::shared_ptr<myClass> arg1)
{
   arg1->someField = 4;
}

Significa lo anterior simplemente incrementar el shared_pt el recuento de referencia y todo es fresco? O deja un colgando puntero?

Son todavía supone que para hacer esto?:

DoSomething(myClassObject.Get());

void DoSomething(std::shared_ptr<myClass>* arg1)
{
   (*arg1)->someField = 4;
}

Creo que la 2ª manera puede ser más eficiente, ya que sólo tiene que copiar 1 dirección (en oposición a todo el puntero inteligente), pero el 1 de manera que parece más legible y no me anticipar empujando los límites de rendimiento. Sólo quiero para asegurarse de que no hay algo peligroso en él.

Gracias.

  • const std::shared_ptr<myClass>& arg1
  • La segunda forma es roto, el primero es idiomáticas, si usted realmente necesita su función para compartir la propiedad. Pero, ¿ DoSomething realmente necesita para compartir la propiedad? Parece que sólo debe tomar un lugar de referencia…
  • Gracias Chet, hace que se incremente el puntero inteligente ref contar?
  • No, pero ¿por qué la función de la fuerza especial de objeto de propiedad semántica en sus llamadores si realmente no los necesita? Su función no hace nada que no sería mejor como void DoSomething(myClass& arg1).
  • La mía es más de una unidad por respuesta. Lamentablemente no tengo el tiempo para proporcionar una adecuada respuesta de explicar los diferentes semántica de pasar punteros inteligentes…por lo tanto, la unidad 😉
  • Lo que yo veo. Yo estoy con ganas de aprender reglas básicas de pulgar acerca de pasar las cosas a su alrededor. Suena como que usted sugeriría que pasa sólo una referencia, a menos que la propiedad es necesaria.
  • Todo el propósito de punteros inteligentes para manejar fuera de lo común la propiedad de los objetos de problemas, si no los tengas, no debería ser el uso de punteros inteligentes en el primer lugar. ;-] Como a shared_ptr<> específicamente, usted debe pasar por el valor con el fin de compartir la propiedad.
  • wow, he oído de otros que raw punteros se deben evitar ahora. Hay dos campos de formación?
  • Nadie está abogando raw punteros — utilizar el almacenamiento automático y referencias, y punteros inteligentes y los valores de otra manera. En el ejemplo, un puntero inteligente no está garantizada.
  • Relacionado: en general, std::make_shared no sólo es más eficiente, pero también seguro que el std::shared_ptr constructor.
  • Relacionadas con la pregunta: stackoverflow.com/questions/327573/…

InformationsquelleAutor Steve H | 2012-05-31

4 Comentarios

  1. 153

    Quiero pasar un compartida puntero a una función. Me pueden ayudar con eso?

    Seguro, me pueden ayudar con eso. Supongo que usted tiene algún conocimiento de la propiedad semántica de C++. Es eso cierto?

    Sí, estoy razonablemente cómodo con el tema.

    Bueno.

    Ok, solo se me ocurren dos razones para tomar una shared_ptr argumento:

    1. La función quiere compartir la propiedad del objeto;
    2. Que la función hace alguna operación que trabaja específicamente en shared_ptrs.

    Que uno está interesado?

    Estoy buscando una respuesta general, así que estoy realmente interesado en ambos. Estoy curioso acerca de lo que significa en el caso #2, aunque.

    Ejemplos de tales funciones incluyen std::static_pointer_cast, personalizada comparadores, o de predicados. Por ejemplo, si usted necesita para encontrar todos los únicos shared_ptr de un vector, usted necesita un predicado.

    Ah, cuando la función que realmente se necesita para manipular el puntero inteligente en sí.

    Exactamente.

    En ese caso, creo que debemos pasar por referencia.

    Sí. Y si no cambia el puntero, que desea pasar por referencia const. No hay necesidad de copiar ya que no es necesario compartir la propiedad. Ese es el otro escenario.

    Ok, lo tengo. Vamos a hablar de el otro escenario.

    La que compartir la propiedad? Ok. ¿Cómo se puede compartir la propiedad con shared_ptr?

    Copiándolo.

    A continuación, la función se necesita para hacer una copia de un shared_ptr, ¿correcto?

    Obviamente. Así que me pase por una referencia const y copia a una variable local?

    No, eso es un pessimization. Si se pasa por referencia, la función no tendrá más remedio que hacer la copia manualmente. Si es aprobada por el valor que el compilador de elegir la mejor opción entre una copia y moverse y realizar de forma automática. Así, el paso por valor.

    Buen punto. Debo recordar que «Quieren Velocidad? Paso por Valor.» el artículo más a menudo.

    Esperar, lo que si la función almacena el shared_ptr en un miembro de la variable, por ejemplo? No se que hacer una copia redundante?

    La función sólo puede mover la shared_ptr argumento en su almacenamiento. Mover un shared_ptr es barato porque no cambia los recuentos de referencia.

    Ah, buena idea.

    Pero estoy pensando en un tercer escenario: ¿qué pasa si usted no desea manipular el shared_ptr, ni a compartir la propiedad?

    En ese caso, shared_ptr es completamente irrelevante para la función. Si desea manipular el pointee, tomar un pointee, y dejar que las personas que llaman recoger lo que la propiedad semántica que quieren.

    Y debo tomar el pointee por referencia o por valor?

    Las normas habituales que se aplican. Punteros inteligentes no cambia nada.

    Paso por valor, si me voy a copiar, el paso por referencia, si quiero evitar una copia.

    Derecho.

    Hmm. Creo que se olvidó de otro escenario. Lo que si quiero compartir la propiedad, sino sólo en función de una determinada condición?

    Ah, un interesante caso extremo. No espero que suceda a menudo. Pero cuando esto sucede se puede pasar por valor y omitir la copia si usted no lo necesita, o paso por referencia y hacer la copia si es necesario.

    Me arriesgo una copia redundante en la primera opción, y perder un movimiento potencial en el segundo. No puedo comer el pastel y tenerlo demasiado?

    Si estás en una situación en la que realmente importa, puede proporcionar dos sobrecargas, uno de tomar una const lvalue de referencia, y otro, tomando un r-value de referencia. Una de las copias, el otro se mueve. Perfecto para el reenvío de plantilla de función es otra opción.

    Creo que cubre todos los escenarios posibles. Muchas gracias.

    • +1, impresionante. Falta de freehand estrellas, aunque. 😛
    • nominación para c++-faq etiqueta
    • Algunos ejemplos de código sería bueno
    • ¿Para qué? Todo esto es acerca de que debo hacer Un o que debo hacer B. Creo que todos sabemos cómo pasar objetos por valor o referencia, ¿no?
    • Porque la prosa como «¿significa eso que voy a pasar por una referencia const para hacer la copia? No, eso es un pessimization» es confuso para los principiantes. Pasando por una referencia const no hacer una copia.
    • No estoy de acuerdo con la regla de «Si desea manipular el pointee, tomar un pointee,». Como se indica en este respuesta no tomar la propiedad temporal de un objeto puede ser peligroso. En mi opinión, el defecto debe ser pasar una copia temporal de la propiedad para garantizar la validez de los objetos para la duración de la llamada a la función.
    • No hay escenario en la respuesta que el enlace se aplica esa regla, por lo que es completamente irrelevante. Por favor me escribe un SSCCE donde se pasa por referencia de un shared_ptr<T> ptr; (es decir,void f(T&), llamado con f(*ptr)), y el objeto no deja de ser la llamada. Alternativamente escribir uno donde se pasan por valor void f(T) y surgen problemas.
    • echa un vistazo a mi ejemplo de código por la sencilla autónomo ejemplo correcto. El ejemplo es para void f(T&) y consiste en hilos. Creo que mi problema es que el tono de su respuesta desalienta a pasar la propiedad de shared_ptr, que es el más seguro, más intuitiva y menos complicada de hacer uso de ellas. Yo estaría muy en contra siempre el asesoramiento de un principiante para extraer una referencia a datos de propiedad de un shared_ptr<> las posibilidades de uso indebido son grandes, y el beneficio es mínimo.
    • El problema en el ejemplo es de una naturaleza diferente: usted tiene los hilos comparten el objeto, pero no les dan de propiedad compartida. Leer esta respuesta claramente y te darás cuenta de que si necesitas compartir la propiedad, pasar un shared_ptr. Creo que mi respuesta anima a no encontrar un whateverst manera de hacer nada, y en lugar de ello invita a pensar acerca de qué diablos estás tratando de hacer. No quiero que los principiantes (o cualquier persona) para el uso de punteros inteligentes sin la comprensión de la idea de propiedad.
    • Tenga en cuenta también que su ejemplo se pasa la referencia a std::ref, y el objeto es el hecho de sobrevivir a la llamada a std::ref.
    • Tener un hilo tire de la alfombra de debajo de otro hilo va a causar problemas, independientemente de lo que pase (¿qué pasa si el main() del hilo mutado el objeto?). Es completamente ajena a shared_ptr. Es un tema que sólo surge cuando se quiere escribir código multiproceso sin pensar.
    • Es que no es ajeno, si la función se llevó un shared_ptr<> entonces ningún accidente podría ocurrir. shared_ptr<> garantiza que los datos que posee validez con independencia de roscado preocupaciones. El otro gran peligro es que la función que se pasa la referencia tiene una copia y almacena más allá de la duración de la llamada, lo cual podría causar problemas sin roscar. Usted está abogando por confiar en la función llamada/objeto con hacer lo correcto, no hay ninguna semántica de la prevención de los mismos. Si un completo shared_ptr<> se pasa, entonces está en su propia cabeza si ellos quieren violar la propiedad de forma explícita.
    • permítanos continuar esta discusión en el chat
    • ¿Qué pasa cuando usted necesita para pasar de un tipo derivado como un tipo de base? Esto requiere punteros correcta?
    • no importa, acabo de leer que hace referencia a evitar la fragmentación del problema.
    • Esta respuesta era difícil de leer. ¿Tiene usted una breve respuesta para pasar un compartida puntero a una función para almacenarse para su uso a través de la vida del objeto? Tal vez debería utilizar el estándar de punteros en lugar de shared_ptr? Básicamente me han objetos a los que debe referirse el uno al otro…
    • almacenarse para su uso a través de la vida del objeto» está cubierto bajo «Espera, ¿qué pasa si la función almacena el shared_ptr en un miembro de la variable, por ejemplo?» Con respecto a que la respuesta no sea difícil de leer, me puede decir qué partes podría mejorar? FWIW, escribí esto bajo el supuesto que el lector ya tiene una cierta comprensión de la propiedad semántica de C++; yo quería centrarme en el argumento de que pasa en concreto, y no tirando de ella explicando la propiedad así.

  2. 17

    Creo que las personas son innecesariamente miedo de usar raw punteros como parámetros de la función. Si la función no se va a almacenar el puntero o de otra manera afectar su vida útil, una cruda puntero funciona igual de bien y representa el mínimo común denominador. Considerar, por ejemplo, cómo se pasa de un unique_ptr en una función que toma un shared_ptr como un parámetro por valor o por referencia const?

    void DoSomething(myClass * p);
    
    DoSomething(myClass_shared_ptr.get());
    DoSomething(myClass_unique_ptr.get());

    Un raw puntero como parámetro de la función no impide el uso de punteros inteligentes en el código de llamada, donde lo que realmente importa.

    • Si usted está usando un puntero, ¿por qué no usar simplemente una referencia? DoSomething(*a_smart_ptr)
    • tienes razón – que sería aún mejor. A veces se necesita para permitir la posibilidad de un puntero NULO, aunque.
    • Si usted tiene un convenio de usar raw punteros como parámetros de salida es más fácil de detectar en el código de llamada de que una variable puede cambiar, por ejemplo: comparar fun(&x) a fun(x). En el último ejemplo x podrían ser pasados por valor o como una constante de ref. Es como se indicó anteriormente también permiten pasar nullptrsi usted no está interesado en la salida…
    • Ese puntero-como-salida-de los parámetros de la convención puede dar una falsa sensación de seguridad cuando se trata con punteros pasado desde otra fuente. Porque en ese caso la llamada es divertido(x) y *x es modificado y la fuente no tiene &x para advertirle.
  3. 3

    Sí, toda la idea sobre un shared_ptr<> es que varias instancias puede mantener el mismo formato de puntero y de la memoria subyacente sólo será liberado cuando la última instancia de shared_ptr<> es destruido.

    Me gustaría evitar un puntero a un shared_ptr<> como que derrota el propósito que ahora trabaja con raw_pointers de nuevo.

  4. 2

    Pasar-por-valor en su primer ejemplo es seguro, pero hay una mejor expresión. Pasar por la constante de referencia cuando sea posible – yo diría que sí, incluso cuando se trata de punteros inteligentes. El segundo ejemplo no es exactamente roto, pero es muy !???. Tonto, no logrando nada y derrotas parte de el punto de los punteros inteligentes, y va a dejar en un buggy mundo de dolor cuando intenta eliminar y modificar las cosas.

    • Si usted necesita una propiedad compartida, que necesita para pasar por valor, de lo contrario usted está realmente no compartir nada. Si usted no necesita una propiedad compartida, entonces no pasa un shared_ptr<>, para empezar.
    • Seguro de si estoy de acuerdo con esto. Se puede producir un caso donde pasa el puntero por sentido y pasar por referencia no en el primer lugar?
    • Nadie está abogando pasando por el puntero, si te refieres a la cruda puntero. Pasar por referencia si no hay ninguna propiedad en disputa es, sin duda idiomáticas. El punto es, con respecto a shared_ptr<> específicamente, que debe hacer una copia con el fin de compartir la propiedad; si usted tiene un de referencia o puntero a una shared_ptr<> entonces no estás compartiendo nada, y están sujetos a la misma vida de las cuestiones normales de referencia o puntero.
    • Pasa una referencia constante es buena en este caso. El original shared_ptr de la persona que llama está garantizado para durar más que la llamada a la función, por lo que la función es seguro en el uso de la shared_ptr<> const &. Si se necesita almacenar el puntero para una hora más tarde, tendrá que copiar (en este punto se debe presentar una copia de hecho, en lugar de mantener una referencia), pero no hay necesidad de incurrir en el costo de la copia de menos que necesita para hacerlo. Me gustaría ir para pasar una referencia constante en este caso….
    • una referencia constante es buena en este caso.» No en cualquier cuerdo API – ¿por qué iba una API mandato de un puntero inteligente tipo que ni siquiera es de tomar ventaja de en lugar de sólo tomar una normal constante de referencia? Eso es casi tan malo como la falta de const-corrección. Si tu punto es que técnicamente no es lastimar a nada, entonces ciertamente estoy de acuerdo, pero no creo que es la cosa Correcta de hacer.
    • … si, por otro lado, la función no es necesario extender el tiempo de vida del objeto, entonces usted puede simplemente eliminar la shared_ptr de la interfaz y pasar una llanura (const) la referencia al objeto puntiagudo.
    • Bien, considero que es una buena guía, mi compañía considera que es una sana orientación (y hay gente realmente inteligente que el trabajo aquí), y heck, incluso Herb Sutter considera que es una buena idea [del segundo día se hable en Ir Nativo de 2012]. Él llama realmente pasando el shared_ptr por valor de un pessimization. A continuación, de nuevo, todo el mundo puede estar equivocado 🙂 C++11 y más allá de la diapositiva 22
    • ¿Qué pasa si su API consumidor no está usando shared_ptr<> para empezar? Ahora su API es realmente sólo un dolor en el cuello, ya que las fuerzas de la persona que llama inútilmente cambiar su tiempo de vida del objeto de la semántica sólo para usar. Yo no veo nada vale la pena defender que, más allá de decir que «no es técnicamente lastimar a nada». Yo no veo nada controversial acerca de » si usted no necesita una propiedad compartida, no uso shared_ptr<>‘.
    • Creo que he cubierto que en un comentario anterior, si no hay necesidad de extender el tiempo de vida (es decir, no copias de la shared_ptr será tomada), a continuación, pasar a un plano de referencia. Pero, desde su primer comentario: Si usted necesita una propiedad compartida, necesita pasar por valor, de lo contrario usted no está realmente compartir cualquier cosa es falso, usted necesita para pasar el compartidas puntero const referencia y luego hacer una copia. Tenga en cuenta que la vida útil de los parámetros de la función (es decir, la copia en el paso por valor) nunca va a durar más que la vida de la original shared_ptr, por lo que la copia extra es innecesario.
    • creo que he cubierto que en un comentario anterior» de acuerdo, me fue (probablemente innecesariamente) re-ephmasizing. «… necesita pasar por la constante referencia a la compartida puntero y, a continuación, hacer una copia.» Esto no tiene sentido — ¿cómo es semánticamente diferente de lo que se pasa por valor, aparte de hacer lo posible para que la persona que llama a renunciar a la propiedad mediante el movimiento (que es una buena cosa)? EDIT: malinterpretado tu última frase.
    • permítanos seguir esta discusión en el chat, pero básicamente lo que están pagando el costo de un átomo de incremento y ganando nada fuera de ella.
    • Tenga en cuenta que si está garantizado que usted necesita una copia de un parámetro, el paso por valor es una optimización más pase por referencia, por lo que la copia es parte de la interfaz pública.
    • Que es un problema menor para los tipos con referencia semántica. En particular, existe un número limitado de casos donde se quiere copiar (guarde en un miembro?) como la copia y el original son el mismo objeto. Incluso entonces, usted necesita tomar el argumento por valor de forma explícita y mover dentro de la función (de nuevo, el destino de la copia nunca será una variable local a la función).
    • son limitados los casos donde se desea copiar» Si usted no desea copiar, probablemente no necesita una smart ptr como un parámetro.
    • A menos que usted desea obtener un weak_ptr, por ejemplo. Discusión de casos de esquina en realidad no tiene sentido. Ya he mencionado antes de que el cambio de la firma para tomar una referencia en lugar de un puntero inteligente podría ser el camino a seguir…
    • Podemos mover esta discusión aquí: chat.stackoverflow.com/rooms/11966/…

Dejar respuesta

Please enter your comment!
Please enter your name here