Careful: Passing STL containers as parameters might lead to MLE

Revision en3, by Mindeveloped, 2024-01-31 14:12:27

Hello, everyone. I'd like to share an issue I met recently of which passing an STL container as a parameter through a function call caused MLE.

Look at this submission: 244198211. I was debugging it when I realized such line is causing MLE.

void insert (int p, string str, int len, int i, int id) {

I thought passing a string as a parameter might be the problem, so I changed my code and passed the index instead, and it got AC (there are other bugs but they don't matter): 244220216

So why is the problem?

The problem is, passing a parameter in non-reference calls the copy constructor and the destructor of the object each once, which means the object is being copied once every function call until it's finished. In normal situations it doesn't seems to be a big problem, but when you try to pass the object multiple times (especially if you're calling the function recursively) the memory usage is getting stacked up.

Note that this situation is the most common that people prefer to pass STL containers, especially string and vector in function parameters.

To make it clear I did some experiment, shown below:

#include<iostream>
using namespace std;

struct node {
	node () {
		cout << "Constructor called" << endl;
	}
	node (node &obj) {
		cout << "Copy constructor called" << endl;
	}
	~node () {
		cout << "Destructor called" << endl;
	}
};
node x;
void normal (node y) {
	cout << "Normal function body" << endl;
}
void reference (node &y) {
	cout << "Reference function body" << endl;
}
int main () {
	cout << "Calling normal function" << endl;
	normal (x);
	cout << "Finished calling normal function. Calling reference function" << endl;
	reference (x);
	cout << "Finished calling reference function" << endl;
	return 0;
}

And the result is:

Constructor called
Calling normal function
Copy constructor called
Normal function body
Destructor called
Finished calling normal function. Calling reference function
Reference function body
Finished calling reference function
Destructor called

From upon you can see that passing object as normal parameter calls copy constructor and destructor each once, and passing as reference does not do anything to the object.

So here are some suggestions to avoid this:

  1. Pass indices or pointers instead of the original object. The straightforward way, though it might makes the code look bad (imo).
  2. Use arrays instead of strings or vectors. Arrays are passed as pointers of the initial address (in other ways, they are passed as references automatically).
  3. Pass reference if you can. It makes the code more readable compared to 1.

EDIT: The idea was originally wrong, but thanks to the guy in comment I've corrected. The point is still valid, but the description needs a bit changing.

Thanks for reading.

History

 
 
 
 
Revisions
 
 
  Rev. Lang. By When Δ Comment
en3 English Mindeveloped 2024-01-31 14:12:27 622
en2 English Mindeveloped 2024-01-31 12:28:00 3 Tiny change: '.\n3. Passing reference' -> '.\n3. Pass reference'
en1 English Mindeveloped 2024-01-31 12:26:56 2629 Initial revision (published)