Question

If I have a class that contains a vector of another class and I'm expecting it to be very long:

class NucleotideSequence{
private:
    std::string Name;
    std::vector<Nucleotide> Sequence;
public:
    NucleotideSequence();
    NucleotideSequence(std::string name, std::vector<Nucleotide> seq);
    std::string getName();
    Nucleotide* getBase(int pos1);
    int getLength();
    void print();
};

In this case the vector Sequence, do I need to dynamically allocate it by making Sequence *Sequence and making a new vector during the constructor? I want to make sure I use the right resource (stack vs heap) for large vectors (over hundreds of thousands of elements). Which is the right thing to do? I heard vectors wrap the dynamic array allocation.

EDIT:

I've provided the updated code below to show I've used reference passing for the constructor. I hope to use a move constructor too so I can make these objects in a function and then move them outside.

Also given is the updated getPos method which throws the error if the position does not exist in the sequence.

class NucleotideSequence{
private:
    std::string Name;
    std::vector<Nucleotide> Sequence;
public:
    NucleotideSequence();
    NucleotideSequence(const std::string &name, const std::vector<Nucleotide> &seq); // Note that a pointer is not needed since the std::vector class allocated memory on the heap for us and is a wrapper for that whole RAII process.
    std::string getName();
    Nucleotide getBase(int pos);
    int getLength();
    void print();
};

NucleotideSequence::NucleotideSequence(const std::string &name, const std::vector<Nucleotide> &seq)
{
    Name = name;
    Sequence = seq;
}

// Get a specific base
Nucleotide NucleotideSequence::getBase(int pos)
{
    for(std::vector<Nucleotide>::iterator i = Sequence.begin(); i != Sequence.end(); i++)
    {
        if(pos == i->getPos())
        {
            return *i; // Return the correct nucleotide object.
        }
    }
    throw BoundsError(); // If the desired position is not found, throw the error.
}

Thanks, Ben.

Was it helpful?

Solution

I would say it is better to keep your variable member Sequence as a std::vector (and not a pointer to std::vector). As you mentioned "vectors wrap the dynamic array allocation": std::vector manages for you the memory (heap allocation / deallocation / reallocation) in a RAII fashion:
When you write: std::vector<Nucleotide> Sequence, Sequence stores the objects Nucleotide on the heap (not on the stack)

One suggestion: in your constructor, you are passing the std::vector by value (as well as the std::string). Passing by value is expensive if your std::vector has a large size. You need to consider if passing by reference can be applied in your case.

OTHER TIPS

All vectors are on the heap and allocated dynamically. The way you have it declared is fine, but you probably should initialize it in your constructor anyway.

NucleotideSequence... I bet it's a big array.

Yes, wraps the whole dynamically allocated array thing. You dont need to dynamically allocate one, and its usually wrong to do so. Just declare them as straight data members like you have.

But, vectors use value semantics, and thus there is a potential down side of doing this, in that the resulting class will be very expensive to copy/assign (much the way large vectors are expensive to copy/assign).

This is usually fine, it just makes it a large things, and large things are just usually passed by reference when passing them around, so make sure you pass your sequence around by reference, not pass it around by value. (And of course you have provided no copy-ctr/assignment operator, so you were likely going to do this anyway)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top