Избегание временного создания только ради передачи по значению

#c

#c

Вопрос:

Допустим, мне нужно вызвать код в API, которым я не владею. Указанный код принимает некоторые параметры только по значению. Пример:

 class PleaseUseReferences
{
    void DoSometing(VectorFloat passedByValue);
}
  

на стороне вызова я должен теперь сделать либо:

 PleaseUseReferences pus;
pus.DoSometing(VectorFloat(0.0f,0.0f,0.0f));
  

или

 PleaseUseReferences pus;
VectorFloat unnecessaryTemporary(0.0f,0.0f,0.0f);
pus.DoSometing(unnecessaryTemporary);
  

в любом случае я получаю два вызова конструктора. Один на стороне вызывающей стороны, а затем другой конструктор копирования для аргумента, который был передан по значению.

С пониманием того, что

  1. Я не могу изменить API, который был мне предоставлен, и я не могу изменить содержащийся в нем код.
  2. Я знаю, что временное бесполезно после вызова.

Есть ли способ сэкономить на этом первом вызове конструктора?


В приглашении от @cigien я опробовал два сценария.

Вот код, который я использовал, он демонстрирует, о чем говорил @cigien :

 // Example program
#include <iostream>
#include <string>

class Vector
{
    public:
    Vector(int x, int y)
    {
        printf("nConstructor");
        m_x = x;
        m_y = y;
    }
    
    Vector(const Vectoramp; other)
    {
        printf("nCopy Constructor");
        m_x = other.m_x;
        m_y = other.m_y;
    }
    
    static void HorriblePrint(Vector v)
    {
        printf("nx : %d y : %d", v.m_x , v.m_y);
    }
    
    int m_x,m_y;
};

int main()
{
    printf("nWith Temporary");
    printf("n****************");
    Vector v(0,0);
    Vector::HorriblePrint(v);
    printf("n****************");
    
    printf("nnnWithout Temporary");
    printf("n****************");
    Vector::HorriblePrint(Vector(1,1));
    printf("n****************");
    
}
  

Вот результат

 With Temporary
****************
Constructor
Copy Constructor
x : 0 y : 0
****************


Without Temporary
****************
Constructor
x : 1 y : 1
**************** 
  

Комментарии:

1. Не должно быть никаких копий, с pus.DoSometing(VectorFloat(0.0f,0.0f,0.0f)); которыми это должно справиться.

2. Что заставляет вас думать, что вызов конструктора занимает значительное количество времени?

3. Я просто использовал VectorFloat в качестве примера. В реальном варианте использования, который я рассматриваю, конструктор значительно сложнее @Sneftel

4. ^ обе эти точки. Оптимизация компилятора должна предотвращать две копии, и выполнение копии, вероятно, в любом случае займет незначительное количество времени. Скажите, вы сначала измерили?

5. В первом примере, использующем a temporary, даже не будет копий без оптимизации компилятора. Предположение не доказано.

Ответ №1:

в любом случае я получаю два вызова конструктора. Один на стороне вызывающей стороны, а затем другой конструктор копирования для аргумента, который был передан по значению.

Не обязательно. Например:

  1. Если тело метода доступно как часть той же единицы преобразования, весь вызов может быть пропущен.
  2. Если включена оптимизация времени соединения, то снова функция может быть исключена.
  3. Начиная с C 17, в стандарте C , похоже, есть формулировка об исключении копирования анонимных временных файлов. Хотя я не уверен в этом на 100%, и это может зависеть от ABI.

Кроме того, помните, что «преждевременная оптимизация — корень всего зла». Вероятно, более важно, чтобы эта часть вашего кода была читаемой и поддерживаемой. Я предполагаю, что 3-сторонний API не будет вызывать дорогостоящее копирование какого-либо большого объекта.

Комментарии:

1. На самом деле, это не » исключение копирования анонимных временных файлов». Нет временного исключения даже из c 17. Вместо этого аргумент является значением prvalue, которое материализуется только там, где это необходимо. И я думаю, что это относится к случаю OP.

2. «Я предполагаю, что 3-й сторонний API не заставит дорогостоящее копирование какого-либо большого объекта». Можно было бы надеяться. К сожалению, здесь это не так.

3. @Vidrohi Есть ли у типа API конструктор перемещения?

4. @Caleth Это не так, но предположим, что это так? (Кажется, вам есть чем поделиться, и мне любопытно)

5. @Vidrohi если ни один из конструкторов копирования или перемещения или присваивания не объявлен, он неявно сгенерирован. Перемещение вектора — это несколько манипуляций с указателем, независимо от количества элементов