0

where I need to change the internal variable to refer to new objects, then do something, then again change the object, and then do something on the new value.

class dml
{
     void setTrain(matrix<T> train_x , matrix<T> train_y)
     {
          train_x_ = train_x;
          train_y_ = train_y;
     }
     void train();

     private:
          matrix<T> train_x_;
          matrix<T> train_y_;
}

So, I will first set train , then call train, which uses the values that I just set to train. Then later on I might change the values, by calling setTrain on new values and I want to run train on that data again. ( For people from ML, I want to implement mini batches, where I feed in data, train on it, then feed in the next batch of data and then train on it) The simple solution that I have right now is stupid, as it involves the copying of a very large matrix. I pointers are the easy solutions that come to mind, but I would prefer not to use them. My program is pretty complex and pointers and mem allocation will only be more trouble. One Idea I though about is :

     private:
          matrix<T>& train_x_;
          matrix<T>& train_y_;
}

Ofcourse this does not work, as reference cannot ever point to null value and I have to initialize them in the constructor and since they cannot be re-bound, there is no point in using them.

I think the solution would be in using some of the smart pointers. But smart pointers are used to manage the memory in heap, but I am not allocating an memory in the heap. The matrix object is created in the stack, but it is implemented using a std::vector, which initializes all of its objects in the heap.

I think logically shared_ptr should work, as we are sharing a varaible. std::make_shared seems to be a good idea, but I read that it too creates a copy when you try create a shared_ptr from an existing object in the stack. But this does not solve the problem of having to copy such a large object.

Another obvious thing is std::move, but move does not apply here, as I might need to use the train data agian, outside of the function call.

I am certain that I am missing something obvious. I am kind of sleep deprived right now, so any solutions would help me out a lot !

Just to clarify:

LargeObj a=9;
auto a_ptr=std::make_shared(a);

If I do this, then a_ptr will just point to a, without creating a copy? But this is not what one of the answer here says:

Create a boost::shared_ptr to an existing variable

int a = 3; // Existing variable shared_ptr aCopy = make_shared(a); //Create copy with value of a

Community
  • 1
  • 1
nnrales
  • 1,481
  • 1
  • 17
  • 26
  • 1
    How about using move semantics? You can delete the copy constructor and copy assignment operator for `matrix` and then just use the move operator after construction. – wally Dec 13 '16 at 16:20
  • @flatmouse nope. I need the matrix outside. I don't want it moved. I have added that comment. – nnrales Dec 13 '16 at 16:21
  • 1
    So then why not add a function to get a reference to the matrices if you need them outside? The main question here is where the ownership of the matrices resides. Once you have that answer the rest will be easier to reason about. – wally Dec 13 '16 at 16:23
  • @flatmouse hmm. The ownership is outside the class. dml only has references to these objects, not ownership. ( logically ) – nnrales Dec 13 '16 at 16:25
  • 1
    Then you should use smart pointers. Your concerns about the heap seem unfounded. – wally Dec 13 '16 at 16:26
  • @flatmouse So create the matrix objects in the heap and keep smart pointers to them? Can we keep smart pointers to objects on the stack without copying etc ? – nnrales Dec 13 '16 at 16:27
  • 1
    Yes, `std::shared_ptr` will not create a copy of the underlying object. – wally Dec 13 '16 at 16:28
  • @flatmouse I have been burn a lot in the past by using a lot of new s. I would like to avoid that. – nnrales Dec 13 '16 at 16:28
  • 1
    You don't need to use `new` with `std::shared_ptr`. – wally Dec 13 '16 at 16:28
  • @flatmouse I added more to the questions. Just to make sure we are on right page, can you just read the code snip that I added last. – nnrales Dec 13 '16 at 16:38

1 Answers1

1
LargeObj a=9;
auto a_ptr=std::make_shared(a);

If I do this, then a_ptr will just point to a, without creating a copy?

If you create a shared pointer by copying from an existing object (that allows it) then you will have two objects. This can be avoided by deleting the relevant functions in the class and/or by not ever defining the object as anything other than a shared_ptr<matrix<T>>.


You can work with large objects and prevent copying if you use std::shared_ptr.

The following is an adaption of the example in the question. It creates the objects as std::shared_ptrs and shows how they can be assigned to the class in the example.

#include <memory>
#include <iostream>
#include <string>

template <typename T>
class matrix {
public:
    matrix() = default;
    matrix(const matrix&) = delete; // no copy
    matrix(matrix&&) = default; // allow move
    matrix& operator=(const matrix&) = delete; // no copy
    matrix& operator=(matrix&&) = default; // allow move
};

template <typename T>
class dml
{
public:
    void setTrain(std::shared_ptr<matrix<T>> train_x_ptr, std::shared_ptr<matrix<T>> train_y_ptr)
    {
        train_x_ = train_x_ptr;
        train_y_ = train_y_ptr;
    }
    void train() {};
private:
    std::shared_ptr<matrix<T>> train_x_{}; // starts out as an empty shared pointer (contains nullptr)
    std::shared_ptr<matrix<T>> train_y_{}; // starts out as an empty shared pointer (contains nullptr)
};

int main()
{
    // no explicit new, object is created on the heap (train_x_ptr is created on the stack,
    // but will be copied to dml without copying the underlying object).
    auto train_x_ptr{std::make_shared<matrix<int>>()}; 
    auto train_y_ptr{std::make_shared<matrix<int>>()};
    dml<int> d;
    d.setTrain(train_x_ptr, train_y_ptr);
}

Note that new is not used directly.

I think the solution would be in using some of the smart pointers. But smart pointers are used to manage the memory in heap, but I am not allocating an memory in the heap. The matrix object is created in the stack, but it is implemented using a std::vector, which initializes all of its objects in the heap.

In this example the std::shared_ptr will create matrix on the heap and manage the lifetime for you. At the same time, if matrix contains a std::vector those elements will also be on the heap somewhere, managed by std::vector.

I think logically shared_ptr should work, as we are sharing a varaible. std::make_shared seems to be a good idea, but I read that it too creates a copy when you try create a shared_ptr from an existing object in the stack. But this does not solve the problem of having to copy such a large object.

It will not create a copy. It does solve the problem.

wally
  • 10,717
  • 5
  • 39
  • 72
  • Thanks. A final question. I need copy to be implemented for matrix , sp I can't delte it . Does it matter ? – nnrales Dec 13 '16 at 18:22
  • 1
    No, it doesn't matter. You just have to be aware of how the pointers are created to avoid creating a copy you didn't want. – wally Dec 13 '16 at 18:24
  • Plus : Here too you are creating a new object to use with the shared_ptr, can it point to a preexisting data element ? Do we have anything in cpp other that a pointer which does this ? – nnrales Dec 13 '16 at 18:25
  • 1
    If you have an existing object that cannot be initially created within a shared pointer then you might just have to use regular pointers with their attendant risks. Or maybe you can use references in the `dml` class (initialize in the constructor), but create a new `dml` instance when you need different members pointed to. – wally Dec 13 '16 at 18:37
  • Thank you. Pointers still have their uses I suppose. – nnrales Dec 13 '16 at 18:53