Q:

About dynamic memory in C++

This is the program I wrote in response to an exercise in C++ Primer. I don't know why it prints the last number in the vector twice.
vector<int>* create_dyn_vec() {
    return new vector<int>();
}
void give_value(vector<int>* ivec_ptr, istream& in) {
    int i;
    while (in) {

        in >> i;
        ivec_ptr->push_back(i);
    }
}
void print(vector<int>* ivec_ptr) {
    for (auto& i : *ivec_ptr)
        cout << i << " " << endl;
}

int main() {
    auto ivec_dyn_ptr=create_dyn_vec();
    give_value(ivec_dyn_ptr, cin);
    print(ivec_dyn_ptr);
    delete ivec_dyn_ptr;
}

A:

For your immediate problem of duplicated last number, replace
while (in) {
    in >> i;

with just
while( in >> i ) {

The original code doesn't check whether the input operation succeeds, before it appends the number to the vector. Thus at the end of the file, where the input operation fails, the number is unchanged, and is appended.
In the replacement code the expression in >> i attempts the input operation and produces a reference to the stream as its expression result. The reference is used as the while condition, and when used as a condition it's converted to bool. That conversion is defined by the stream as producing not in.fail(), where fail is the member function that tells you whether the last i/o operation on this stream failed or succeded.

Tip: Instead of passing pointers around you can use C++ references.

With more idiomatic C++ this code would be like …
void load_from( istream& in, vector<int>& v )
{
    int i;
    while( in >> i )
    {
        v.push_back( i );
    }
}

void print( vector<int> const& v )
{
    for( auto const& i : v )
    {
        cout << i << endl;
    }
}

int main()
{
    vector<int> v;
    load_from( cin, v );
    print( v );
}

Note that there are no new or delete expressions here. Much of the point of using collection classes like vector is that it automates memory management. Adding manual memory management on top rather defeats the purpose.
Disclaimer: I've not tried to compile the code.

A:

Because the end of the file condition on a std::istream is set after you attempt to read from it, not before:
while (in) {

    in >> i;
    ivec_ptr->push_back(i);
}

After you've read the last value in the file, you restart the while loop again:
while (in) {

This evaluates to true, because the end of the file condition has not been reached yet.
    in >> i;
    ivec_ptr->push_back(i);

You then attempt to read the next value. This attempt fails, and sets the end of file condition on the std::istream. But you push_back() the value to the vector nevertheless. This happens to be the last value you've read in the file, effectively appending it a 2nd time, to the vector.
On the next iteration, the end of the file condition terminates the while loop.

