Of course for any production code you should rely on a robust library implementation that's already withstood the test of time.
That said, for self-teaching it can be fun to write one yourself. I've done it before.
The most efficient way I know of is to use a similar approach to what most resizable collections do internally: store an array, which is increased in size (typically doubled) as needed when the collection's size reaches the length of the array.
A queue is a bit different from an ordinary collection, though, because you want to be able to pop off from the opposite end from where elements are pushed.
Obviously, to remove the first element and shift all other elements down one index would be costly and pointless. So instead you keep track of the starting and ending indices yourself. When the collection reaches the end of the array you use %
to start pushing elements back at the beginning.
The key is simply working out your math so that you handle all cases, e.g., correctly growing the array when the queue is full, getting your bounds checks right, incrementing the start index (or looping back to 0) on every pop, etc.
Clearly, the design I've described above has many limitations: thread safety, for example. But for a simple, single-threaded, efficient implementation, it's a pretty good starting point.
Good luck -- and I also recommend posting your code if/when you've got one that you think is working!