-2

Not so far I discovered, that I completely have no clue about nature of std::vector.

Let me explain:

Vector is growable, right? That means, inside it must somehow allocate/reallocate memory dynamically. Something like this:

class vector {
private:
    int *data;
};

Okay. But such definition implies the fact that if we pass std::vector to another function by reference or by value -- there will be no difference between this two types of parameter passing, and both function will be able to modify data (unless vector is passed as const).

BUT! I tried the following and my idea failed:

void try_to_modify(vector<int> v) {
    v[2] = 53;
}

int main() {
    vector<int> v(3);
    v[2] = 142;
    try_to_modify(v);
    cout << v[2] << '\n';    // output is: 142

    return 0;
}

So where's the truth? What std::vector really is?

Thank you.

vortexxx192
  • 929
  • 1
  • 9
  • 24
  • 2
    Look at an implementation. For example, libc++. It does a deep copy like one would expect. – chris Aug 10 '14 at 06:37
  • 9
    You're forgetting that it has a copy-constructor which makes a copy of the data – M.M Aug 10 '14 at 06:38
  • And once again, less-than-obvious implicit semantical quirks of C++ confuse people. (Well done, Mr Stroustrup!) – The Paramagnetic Croissant Aug 10 '14 at 06:39
  • 8
    @TheParamagneticCroissant Uh, no. This behaviour actually makes sense. This isn't a 'quirk'. This is just how value types *should* work. Also, this is the same exact behaviour in C. – Rapptz Aug 10 '14 at 06:42
  • 1
    @TheParamagneticCroissant, When you pass by value, you don't actually pass by reference. Seems pretty straightforward to me. All you have to know is that C++ has value semantics. – chris Aug 10 '14 at 06:44
  • @Rapptz "This is the same exact behaviour in C." - ***um nope?*** that's exactly the reason why OP was confused. In C, if you copy a struct containing a pointer, and you dereference the pointer in the copy, you access the exact same piece of memory, because no automatic deep-copying is performed, only the pointer itself is copied. – The Paramagnetic Croissant Aug 10 '14 at 06:46
  • @chris I don't doubt that value semantics makes sense. The approach to implementating it makes *much less sense,* though. – The Paramagnetic Croissant Aug 10 '14 at 06:47
  • @TheParamagneticCroissant forget that raw pointers exist in C++ and you'll have an easier time of things. The raw pointer is confusing because it does not have any indication whether copying the pointer should also copy the thing being pointed to. Instead, use language constructs where the handle type includes that semantic info. – M.M Aug 10 '14 at 06:48
  • Use `vector& v` instead! – user1436187 Aug 10 '14 at 06:48
  • @MattMcNabb I don't myself use raw pointers often in C++, but OP was specifically asking about a closely related implementation detail. – The Paramagnetic Croissant Aug 10 '14 at 06:48
  • @TheParamagneticCroissant When pointers are copied, they copy to what they point to. This extends to everything else, see [here](http://coliru.stacked-crooked.com/a/67c2ba2100cd1c85). Just because pointers can modify, doesn't mean C doesn't have value types. It does, and the same code (without pointers) would show the same behaviour. – Rapptz Aug 10 '14 at 06:50
  • 1
    @Rapptz I'm not quite sure what you are trying to say . If you copy a pointer in C then you end up with two pointers pointing to the same piece of data (which is not the behaviour of `std::vector`) – M.M Aug 10 '14 at 06:54
  • @Rapptz It seems you are trying to teach me C and you think that I don't know how pointers and value semantics in C work. That's a wrong assumption, I do, and your example is irrelevant because it does not demonstrate what OP was asking. [Here's](http://coliru.stacked-crooked.com/a/64f72b19700abb95) the code demonstrating the behavior what he was talking about. – The Paramagnetic Croissant Aug 10 '14 at 06:54
  • @MattMcNabb I'm saying that this implementation detail isn't a quirk nor should it be considered a quirk. – Rapptz Aug 10 '14 at 06:55
  • 6
    This *is* the exact same behaviour as C. `std::vector` is a value, he passed a value, it gets copied and the function has it's own independent copy. It is not a pointer or reference type. It is a value. Your mental model of `std::vector` as `int*` is terribly, terribly broken and wrong. – Puppy Aug 10 '14 at 07:02
  • 1
    Speed is way less important than getting the correct semantics. – Puppy Aug 10 '14 at 07:39
  • @The Paramagnetic Croissant: Your thinking has the wrong abstraction level for C++. That's like an Assembler programmer complaining about how a `while` loop in C creates confusion by hiding some `JMP` instruction. – Christian Hackl Aug 10 '14 at 11:50
  • @ChristianHackl tell that to OP, not to me. I *know* how vector works, he doesn't. The fact that C++ tries to mix high-level abstractions with low-level stuff which, in addition, misleadingly resembles to the syntax of C, is just an error in the language. It's not that I don't get the rationale behind the working of vector, it's just I think it can be confusing for someone coming from C. – The Paramagnetic Croissant Aug 10 '14 at 14:04
  • @TheParamagneticCroissant: C++ does not mix abstractions when you copy a vector, as long as you get the mental image of a wrapped pointer out of your head. A C++ programmer usually should not care how a vector deals with pointers internally, just like a C programmer usually should not care how a loop translates to assembly instructions. Such background knowledge is handy for some corner cases or special situations, but in the grand scheme of things, the sheer *continuous thinking* about implementation details all the time will eventually hurt your efficiency and code quality. – Christian Hackl Aug 10 '14 at 14:18
  • @ChristianHackl "continuous thinking about implementation details all the time will eventually hurt" `> /dev/OP`. I just wanted to point out what happens when one does so (for whatever reason -- it's irrelevant why). I did not recommend that one does it, but while we are at explaining the implementation, why could I not mention what my opinion about it is? – The Paramagnetic Croissant Aug 10 '14 at 14:19
  • @TheParamagneticCroissant: You are entitled to your opinion about the implementation, and you may be right about it, but IMHO you are wrong when you assign its style or syntax such great importance in the first place when the language very clearly tries to hide it from you as best as possible. – Christian Hackl Aug 10 '14 at 14:37
  • @TheParamagneticCroissant: By the way, if you had designed C++ from scratch, how would you have implemented `std::vector`'s value semantics given the requirements that (1) the standard library must for the most part be implementable in the language itself and (2) the language should be largely C-compatible? It's not clear whether you are questioning value semantics themselves, the language-design requirements or the solution to the requirements. – Christian Hackl Aug 10 '14 at 14:42
  • @ChristianHackl Only the solution to the requirements. Value semantics is important to have in a large-scale language, and the described behavior is also required to achieve the level of abstraction C++ aims to provide. As to the design: personally, I would have made a stricter distinction between C `struct`s and objects of class type (maybe even syntactically), so that one would *expect* that there is a difference when copying a struct or an instance of a class, namely that there are implicit function calls (and potentially other kinds of side effects) going on. – The Paramagnetic Croissant Aug 10 '14 at 14:50
  • There is no conceptual distinction. In both cases, the value is copied and a copy is passed in. The implementation of "copying the value" is irrelevant. – Puppy Aug 13 '14 at 08:56

2 Answers2

7

std::vector is a container, which internally manages its memory and provides a custom copy constructor. In this copy constructor, new memory is allocated and the existing data is copied over, which makes it a expensive operation. If you want to pass a vector without copying the contained data, you can pass by const reference, for example, const std::vector<int>&.

Let's take a look how to implement a basic container like std::vector.

template <typename T>
class MyVector
{
public:
    MyVector (int size)
    : data_ (new T[size])
    , size_ (size)
    {}

    ~MyVector ()
    {
        delete [] data_;
    }

 private:
    T* data_ = nullptr;
    int size_ = 0;
};

If we copy such an object, we'll have two problems. First, as you noticed, the memory will point to the same location. Second, we will have two destructors that will destruct the same memory, resulting in a double-free. So, let's add a copy constructor, which will be invoked whenever a copy is made.

MyVector (const MyVector& other)
: size_ (other.size_)
{
    data_ = new T[size_];
    std::copy (other.data_, other.data_ + size_, data_);
}

MyVector& operator= (const MyVector& other)
{
    // allocate and copy here to allow for self-assignment
    auto newData = new T[other.size_];
    std::copy (other.data_, other.data_ + size_, newData);

    delete [] data_;

    size_  = other.size_;
    data_ = newData;

    return *this;
}

And that's how std::vector works internally.

Anteru
  • 19,042
  • 12
  • 77
  • 121
  • Shouldn't you omit that delete in the copy ctor? it can't ever happen? – Casper Beyer Aug 10 '14 at 07:15
  • Fixed the self assignment. Yeah, don't need the delete in the copy dtor, thanks! – Anteru Aug 10 '14 at 07:20
  • This is a terrible way to implement the copy-assignment. It should be copy-and-swap. – Cat Plus Plus Aug 10 '14 at 07:39
  • Isn't this just a waaaaay overly complicated response to a simple c++ problem? OP isn't asking how wvector works, just why his example doesn't work – user3791372 Aug 10 '14 at 07:41
  • 1
    @user3791372 Ignoring the messed up grammar, "What std::vector in C++ really is?" seems to ask how a vector is implemented. – juanchopanza Aug 10 '14 at 07:45
  • @juanchopanza I think looking at OP's code example shows that a detailed answer about how vector really works is a little above them when the answer to solve the problem (why does my try_to_modify method not work) is answerable ultimately by one char – user3791372 Aug 10 '14 at 07:49
  • 1
    @user3791372 OP clearly wants to know why `std::vector` doesn't show the referential semantics that their imagined implementation would result in. – juanchopanza Aug 10 '14 at 07:52
-1

This isn't so much a problem with vector as it is with pass-by-value and pass-by-reference arguments.

void try_to_modify (vector<int> vec) will send a copy of the original vector to the function and the function operates on a copy. The vector will copy the data when a copy is made. i.e. new pointer to new data.

However, if you define your function as: void try_to_modify(vector<int> & vec) then it will send the exact vector to the function and your function will operate on it.

Passing by reference is much faster for objects and is usually preferable, unless you have a specific need for a copy.

user3791372
  • 4,445
  • 6
  • 44
  • 78