You just met shell word splitting.
If you quote (like you should), all is OK :
$ for line in "${arr[@]}"; do echo "$line"; done
Can be just (don't read lines with for):
$ printf '%s\n' "${arr[@]}"
Output :
hello hello
bye bye
"Double quote" every literal that contains spaces/metacharacters and every expansion: "$var", "$(command "$var")", "${array[@]}", "a & b". Use 'single quotes' for code or literal $'s: 'Costs $5 US', ssh host 'echo "$HOSTNAME"'. See
http://mywiki.wooledge.org/Quotes
http://mywiki.wooledge.org/Arguments
http://wiki.bash-hackers.org/syntax/words
The difference between $@ and $*: "$@" (quoted) expands to each positional parameter as its own argument: "$1" "$2" ... while "$*" expands to the single argument "$1c$2c..." where c is the first character of IFS. Unquoted $* and $@ are undefined; DO NOT use. You almost always want "$@". The same goes for arrays: "${array[@]}"