Różnice w używaniu " const cv::Mat&", " CV::Mat&"," CV::Mat "lub" const cv::Mat " jako parametrów funkcji?

Szukałem dokładnie i nie znalazłem prostej odpowiedzi na to pytanie.

Przekazując macierze opencv (cv::Mat) jako argumenty funkcji, przekazujemy inteligentny wskaźnik. Każda zmiana macierzy wejściowej wewnątrz funkcji zmienia macierz również poza zakresem funkcji.

Czytałem, że przekazując macierz jako referencję const, nie jest ona zmieniana w funkcji. Ale prosty przykład pokazuje, że tak jest:

void sillyFunc(const cv::Mat& Input, cv::Mat& Output){
    Output = Input;
    Output += 1;
}

int main( int argc, char** argv ){
    cv::Mat A = cv::Mat::ones(3,3,CV_8U);
    std::cout<<"A = \n"<<A<<"\n\n";
    cv::Mat B;
    sillyFunc(A,B);
    std::cout<<"A = \n"<<A<<"\n\n";
    std::cout<<"B = \n"<<B<<"\n\n";
}

Wyraźnie, A zmienia się nawet chociaż jest wysyłany jako const cv::Mat&.

Nie dziwi mnie to, ponieważ wewnątrz funkcji I2 jest prosta Kopia inteligentnego wskaźnika I1, a zatem każda zmiana w I2 zmieni I1.

Dziwi mnie to, że nie rozumiem, jaka jest praktyczna różnica między wysyłaniem cv::Mat, const cv::Mat, const cv::Mat& lub cv::Mat& jako argumenty funkcji.

Wiem, jak to obejść (zastąpienie Output = Input; przez Output = Input.clone(); rozwiązałoby problem), ale nadal nie rozumiem powyższego różnica.

Dzięki chłopaki!

Author: herohuyongtao, 2014-05-05

2 answers

To wszystko dlatego, że OpenCV używa Automatyczne zarządzanie pamięcią.

OpenCV obsługuje całą pamięć automatycznie.

Po pierwsze, std::vector, Mat, inne struktury danych używane przez funkcje i metody mają destruktory, które w razie potrzeby dealokują podstawowe bufory pamięci. Oznacza to, że destruktory nie zawsze dealokują bufory, jak w przypadku Mat. Uwzględniają one możliwość udostępniania danych. Destruktor licznik odniesienia związany z buforem danych macierzy. Bufor jest dealokowany wtedy i tylko wtedy, gdy licznik odniesienia osiągnie zero, to znaczy, gdy żadne inne struktury nie odnoszą się do tego samego bufora. podobnie, gdy instancja Mat jest kopiowana, żadne rzeczywiste dane nie są kopiowane. Zamiast tego licznik referencji jest zwiększany, aby zapamiętać, że istnieje inny właściciel tych samych danych. Istnieje również metoda Mat::clone, która tworzy pełną kopię danych macierzy.

Że powiedział, że aby dwa cv::MatS wskazywały na różne rzeczy, musisz przydzielić im pamięć oddzielnie. Na przykład, następujące będą działać zgodnie z oczekiwaniami:

void sillyFunc(const cv::Mat& Input, cv::Mat& Output){
    Output = Input.clone(); // Input, Output now have seperate memory
    Output += 1;
}

P. S: cv::Mat zawiera int* refcount, który wskazuje na licznik odniesienia. Aby uzyskać więcej informacji, zapoznaj się z katalogiem zarządzanie pamięcią i zliczanie referencji:

Mat jest strukturą zachowującą charakterystykę macierzy / obrazu (Liczba wierszy i kolumn, typ danych itp.) oraz wskaźnik do danych. Więc nic nie stoi na przeszkodzie, abyśmy mieli kilka instancji Mat odpowiadających tym samym danym. A Mat przechowuje liczbę referencji, która mówi, czy dane muszą zostać rozdzielone, gdy konkretna instancja Mat zostanie zniszczona.


Różnice między wysyłaniem cv::Mat, const cv::Mat, const cv::Mat& lub cv::Mat& jako argumenty do funkcji:

  1. cv::Mat Input: przekazuje kopię nagłówka Input. Jego nagłówek nie będzie zmieniany poza tą funkcją, ale może być zmieniany wewnątrz funkcji. Na przykład:

    void sillyFunc(cv::Mat Input, cv::Mat& Output){
        Input = cv::Mat::ones(4, 4, CV_32F); // OK, but only changed within the function
        //...
    }
    
  2. const cv::Mat Input: przekazuje kopię nagłówka Input. Jego nagłówek nie będzie zmieniany poza ani wewnątrz funkcji. Na przykład:

    void sillyFunc(const cv::Mat Input, cv::Mat& Output){
        Input = cv::Mat::ones(4, 4, CV_32F); // Error, even when changing within the function
        //...
    }
    
  3. const cv::Mat& Input: podaj odniesienie do nagłówka Input. Gwarantuje, że nagłówek Input nie zostanie zmieniony poza lub wewnątrz funkcji. Na przykład:

    void sillyFunc(const cv::Mat& Input, cv::Mat& Output){
        Input = cv::Mat::ones(4, 4, CV_32F); // Error when trying to change the header
        ...
    }
    
  4. cv::Mat& Input: podaj odniesienie do nagłówka Input. Zmiany nagłówka Input zachodzą poza i wewnątrz funkcji. Na przykład:

    void sillyFunc(cv::Mat& Input, cv::Mat& Output){
        Input = cv::Mat::ones(4, 4, CV_32F); // totally OK and does change
        ...
    }
    

P. S. 2 : muszę zaznaczyć, że we wszystkich czterech sytuacjach (cv::Mat, const cv::Mat, const cv::Mat& lub cv::Mat&), tylko dostęp do nagłówka maty jest ograniczony, a nie do danych, na które wskazuje. Na przykład, można zmienić jego dane we wszystkich czterech sytuacjach, a jego dane rzeczywiście zmienią się poza i wewnątrz funkcji:

/*** will work for all the four situations ***/
//void sillyFunc(cv::Mat Input){
//void sillyFunc(const cv::Mat Input){
//void sillyFunc(const cv::Mat &Input){
void sillyFunc(cv::Mat &Input){
    Input.data[0] = 5; // its data will be changed here
}
 51
Author: herohuyongtao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-18 07:29:32

Kiedy przekazujesz inteligentny wskaźnik jako referencję, możesz teoretycznie zaoszczędzić trochę czasu przetwarzania, ponieważ Konstruktor kopiujący smart pointer nie jest wywoływany.

 0
Author: ivg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-06 02:28:01