Jump to content

  • Log In with Google      Sign In   
  • Create Account

Brother Bob

Member Since 26 Nov 2001
Offline Last Active Today, 03:02 AM

#5209606 Operator Overloading C++

Posted by on 09 February 2015 - 09:16 AM

For operators like operator+ and operator+=, why is it that when it comes to operator+= we return a reference? Where with the operator+ we return a copy of a temporary object? Why don't they both return the same things, either both return a copy or a reference?

The + operator creates a new object from two parameters, while the += operator modifies one of the operands. I'll answer this partly by asking you a questions back: If operator + returns a reference, what should it return a reference to? Keep in mind while answering this that, in the syntax c=a+b, you are responsible for creating c from a and b, and neither a nor b shall be modified inside the operator. Try implementing operator + by returning a reference.


The += operator is different in that in the syntax a+=b, the object a is modified by b inside the operator. Nothing has to be returned in this case, not even a reference, but a reference is commonly returned in order to chain operators or have access to the modified value directly in the same expression.



Also I have a few questions when it comes to the copy assignment operator:
MyObject &MyObject::operator=(const MyObject &obj)

1. Why is there a destructor called when there is no local object being created in the code? What is actually being destroyed here?

Use the debugger to break where the destructor is actually called to identify which object is destructed where. Unless I misunderstand you, you are right that no object should be destructed in this case.



2. When I was reading up on copy assignment operators, I saw that I should have the self-check guard in order to prevent memory leaks and dangling pointers when it comes to objects that use dynamic memory allocation. But I'm wondering do I need this if I know my class is not going to have any dynamic memory stuff? Or is this something I should do just as a "good practice"?

You could do it for performance reasons as well; if the object is expensive to copy (may include other reasons than just dynamic resources) then it may be faster to check for self-assignment than to blindly make an unnecessary self-copy. It all depends on your use case, if you do self-assignment often enough and whether it is worth checking for it or not. 



3. When read about this operator and dynamic memory allocation, the topic of the "copy swap" idiom comes about. Should I only follow this idiom when dealing with dynamic memory, because an exception could get thrown when trying to allocate data? Or is this something I should just practice as well?

As far as I understand, copy-and-swap is mostly for exception safety reasons. If your assignment cannot fail, then copy-and-swap serves no additional purpose for exception safety. This is, again, not necessarily tied to dynamic resources.


Self-assignment and copy-and-swap are tools you should be aware of and know how and when to use, and equivalently know when they aren't needed. Nothing breaks if you use them when it's not needed, but sometimes the tools or some logically equivalent protection is necessary; for example, if self-assignment breaks your objects, you can either add a self-assignment tests or re-structure your program or algorithms such that self-assignment never happens in the first place.

#5208577 Unity basic Script question

Posted by on 04 February 2015 - 02:55 AM

The variable number is a function parameter, and you gave it a value by passing myInt to the function when you called MultiplyByTwo.

#5207823 Low Level Memory Management C++

Posted by on 31 January 2015 - 04:10 AM

You're doing memory allocations with the new and delete operators, not the operator new() and operator delete() functions as I mentioned. Observe the difference in terminology: the new operator is the operator that allocates memory and constructs objects, while the function operator new() is the function used to allocate the memory.

ptr = operator new(sizeof(T) * 5);
new (ptr) T();
operator delete(ptr);

The function operator new() doesn't take any type to allocate because it doesn't work with types and constructed objects, as opposed to the new operator that has to know what type to allocate and construct.

#5207818 Low Level Memory Management C++

Posted by on 31 January 2015 - 03:35 AM

If you're asking how to recreate std::vector with separate memory allocations and object constructions, then you'll do the following:

  1. Allocate memory with the operator new() or malloc() function.
  2. Construct individual objects with placement new.
  3. Destruct objects by calling their destructor.
  4. Release memory with the operator delete() or free() function.

If you're specifically asking about point 3, then destroying an object is as simple as calling the ~T() member function on it (replace T with the class name, or template type parameter you use). Look here for some example memory management: clicky.

#5206767 Why is this taboo?

Posted by on 26 January 2015 - 03:33 PM

This was a double post with replies. The two threads have been merged.

#5206684 Constructor gotcha's?

Posted by on 26 January 2015 - 06:01 AM

One thing that tripped me up in the early days of learning c++ was calling virtual functions in constructors.

Do not call virtual functions in constructors, as they will not work properly!



Depends on what you mean by "not work properly" though. Calling virtual functions in constructors is well defined and well behaved by the language, but may not be obvious or work how you initially expect it work. I suspect that the problem was a lack of understanding of what will happen, rather than it "not working properly".

#5206361 Constructor gotcha's?

Posted by on 24 January 2015 - 04:15 AM


the order of initialization in constructor initializer lists is the *member declaration order*, not the order in which members are lexically arranged in the initialization list.


so if i have member variables:

int a;

int b;


and in my constructor i say:




it will process a=b*2 first?


don't recall if i heard of that one before or not. then again, i first learned c++ syntax when it first came out, and haven't really used it much since. so maybe its just yet another thing that i've already forgotten.


No, that is assignment but Josh is talking about initialization and the initializer list.

struct foo {
    foo() : b(5), a(b*2) {}
    int a;
    int b;

In this class, a is declared before b and therefore a is also initialized with twice the value of b, before b has been initializer. Code in the constructor is executed top-down, but that code is executed after the initializer list.

#5206171 Textured cube with glDrawElements

Posted by on 23 January 2015 - 04:47 AM

A cube with more attributes than just position ultimately has 24 unique vertices. If you build the sides of the cube using triangles, you have to generate a total of 32 vertices. However, the shared edge of the two triangles per side also share unique vertices so out of the 32 vertices you need to generate there are only 24 unique ones.


So you can still gain something by using indexed primitives because some of the triangles share unique vertices. On the other hand, a cube is close to the worst case for indexed primitives because it only has sharp edges with discontinuous vertex attributes that prevents vertex sharing. Compare to smooth surfaces, such as a sphere, where attributes typically flow smoothly across the surface most of the time.

#5205632 Serving large files over TCP

Posted by on 20 January 2015 - 03:17 PM

Unless my understanding of TCP is completely wrong, if I send a huge chunk, TCP can split them up and piece them back together on their end, and that's TCP's job.  But in this case, I purposely split the packets myself, so as far as I understand, TCP sees the packets independently.  Am I correct/wrong on this?


If you mean that a single call to send() [or equivalent function] may split your buffer and transport it with multiple IP packets and the receiver is required to assemble it back in order, then you are correct. If you also mean that two buffers sent by two different calls to send() may arrive out of order at the receiver end, then you are mistaken.


Your data may arrive out of order on the IP level since individual IP packets are independent in that sense, but the two buffers will ultimately be delivered to you in order on the TCP layer. Your mistake is that you see TCP as a message or packet-based protocol. It is not, it is a stream-based protocol; you send a stream of data and you receive a stream of data. Any splitting into packets or individual messages happens only on the IP level when the TCP stream is transported by IP packets. This is all managed by the TCP layer for you: stream in, stream out.


Forget about packages when talking about TCP. There is only a stream you put data into and/or get data from. A single call to send() may be split into multiple IP packages, or multiple calls to send() may be combined into a single IP packet, when the data is actually transmitted. Likewise, there is no requirement to match a call to send() by a call to recv(). You can receive your data in any buffers you like, independent on what and how much you send. This is an entirely different concept from UDP.


You may, for other reasons, have to implement a separate messaging protocol on top of TCP, but that's a different issue. Your issue was effectively about different send() calls arriving out of order from the TCP layer, and that's not correct.

#5204351 What is the gradient symbol for

Posted by on 14 January 2015 - 06:49 PM



Where did the extra factor of `rlen' come from?

Its the distance vector between two particle positions and rlen is the magnitude of this vector.


What I mean is that
final float term = 45.0f / ((float)Math.PI * (float)Math.pow(kH, 6) * rlen);
should probably be
final float term = 45.0f / ((float)Math.PI * (float)Math.pow(kH, 6));
Unless you can explain where "the extra factor of rlen" came from.


Observe the different symbols in his equations: the argument to the function is r (bold and upface) which is presumably a vector, whereas the equations contain r (normal weight and slanted) that is used in a scalar context. His code maps to his equation under the assumption that r=|r|.

#5203875 How can sample rate be 44000Hz?

Posted by on 13 January 2015 - 04:28 AM


. And depending on the "width" of the middle region, you must keep a margin between the highest frequencies in your original signal and half the sampling rate (essentially what Aressera already said).


How is that "margin" between the highest frequencies and half the sampling rate measured? One is a continuous signal(?) while the other is a digital signal(samples per second.)


If you have a sampling rate of 44 kHz, the Nyquist frequency is at 22 kHz. Since your anti-aliasing and reconstruction filter has a transition band (the middle part mentioned earlier) between the pass band and the rejection band, the effective cutoff frequency of the filter has to be lower. Say that you have a cutoff at 18 kHz and a rejection band starting at 22 kHz (a filter passing from 0 to 18 kHz, blocking from 22 and up in this case since you want to eliminate everything above 22 kHz); that means the middle part gives you a margin of 22-18=4 kHz. Your analog signals are therefore effectively limited to 18 kHz, despite having a Nyquist frequency of 22 kHz.

#5203778 Should I use the gradient to get the Normal of a Sin wave?

Posted by on 12 January 2015 - 04:02 PM

Look here for the equation of a surface normal. The normal at a point (x,z) of the function f(x,z) is (fx(x,z), -1, fz(x,z)) given your notation. Note that your fy should be -1 according to the link, not 0 as in your example.

#5199949 intersection of two lines

Posted by on 25 December 2014 - 04:46 AM

Consider all points on a lined defined as s+t*v, where s is a single point on the line, v is the direction of the line, and t is a parameter that produces points along the line. In your code, where you have two points, you can just define s=p0 and v=p1-p0. If t=0, then p=p0; if t=1, then p=p1, and so on.


You want to find the intersection point between two line segments, which is a point common to two line segments. Thus, you have the two lines

  • s0 + t0 * v0, where s0 = p0 and v0 = p1-p0 from your code, and
  • s1 + t1 * v1, where s0 = p2 and v0 = p3-p2 from your code.

Find a common point along the two lines by solving for t0 and/or t1 from

  • ​s0 + t0 * v0 = s1 + t1 * v1

This is a normal linear equation system, so rearrange and reformulate the problem on matrix form.

  • t0 * v0 - t1 * v= s1 - s0
  • [v0, -v1] * [t0, t1]T = s1 - s0

Note that I assume column vectors here, and that the V-matrix is a 2-by-2 matrix where the two vectors v0 and v1 are the columns of the V-matrix. Finally, solve for t0 and t1.

  • [t0, t1]T = [v0, -v1]-1 * (s1 - s0)

When you have t0 and t1, just plug any of them back into the corresponding lines to find the intersection point. Both of them will produce the same point.


Now that we have the theory, you can identify the maths with the code:

  • My direction vectors v0 and v1 corresponds to your s1 and s2.
  • My (s1 - s0) corresponds to your u, although there is a sign difference here that will be cancelled later, so no worries.
  • Your ip is the determinant of my [v0, -v1]-1.
  • Your s and t are the x and y coordinates of the multiplication of my V-matrix and (s1 - s0).
  • Your i being assigned inside the if-statements is when you plug one of the t's into its corresponding line equation to produce the intersection point.
  • The first if-statement checks if the resulting points are outside of the two line segments bounded by the two points. That happens when t<0 or when t>1. Remove that if-statement if you want the lines to extend indefinitely.

The theory above to find the intersection point is equally valid for 3-dimensional lines as well. It will, however, find the points along the two lines that are closest to each other, and you need to find some other method to invert the V-matrix since it's no longer square; for example, the pseudo-inverse.

#5199239 I need help with some maths

Posted by on 20 December 2014 - 06:18 AM

Start by assuming that the circle is centered at the origin; thus, translate everything by -p, and your click point becomes t-p. Now you can just normalize the point t-p so that it ends up on the edge of the unit circle, and then multiply by the desired radius for your desired circle. Finally, translate that point back by p to negate the initial translation by -p.


In short, using vector maths:

x = p + r*normalize(t-p);

#5198734 constructor for class that contains another class and constructor C++

Posted by on 17 December 2014 - 03:16 AM

As BitMaster said, the base class is responsible for initializing itself. You don't initialize the base class from derived classes, but instead you delegate the work to it from the derived class' constructor.

template <class _cType> class  t4dpoint : public t3dpoint<_cType> {
    _cType w;
    // the t3dpoint base class is automatically default initialized if not specified, and then initialize our own member
    t4dpoint<_cType>() : w(1.0)
    { }
    // initialize the t3dpoint base class and then initialize our own member
    t4dpoint<_cType>(_cType x, _cType y, _cType z, _cType w) : t3dpoint(x,y,z), w(w)
    { }